From 279f0d568dd96dc4966ebc6862cd2ec0562d742b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 1 Oct 2016 01:26:49 +0200 Subject: [PATCH 001/157] rtio: support differential ttl --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index b8c759ce9..018762984 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -4,7 +4,7 @@ from artiq.gateware.rtio.phy import ttl_serdes_generic class _OSERDESE2_8X(Module): - def __init__(self, pad): + def __init__(self, pad, pad_n=None): self.o = Signal(8) self.t_in = Signal() self.t_out = Signal() @@ -12,20 +12,27 @@ class _OSERDESE2_8X(Module): # # # o = self.o + pad_o = Signal() self.specials += Instance("OSERDESE2", p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - o_OQ=pad, o_TQ=self.t_out, + o_OQ=pad_o, o_TQ=self.t_out, i_CLK=ClockSignal("rtiox4"), i_CLKDIV=ClockSignal("rio_phy"), i_D1=o[0], i_D2=o[1], i_D3=o[2], i_D4=o[3], i_D5=o[4], i_D6=o[5], i_D7=o[6], i_D8=o[7], i_TCE=1, i_OCE=1, i_RST=0, i_T1=self.t_in) + if pad_n is None: + self.comb += pad.eq(pad_o) + else: + self.specials += Instance("OBUFDS", + i_I=pad_o, + o_O=pad, o_OB=pad_n) class _IOSERDESE2_8X(Module): - def __init__(self, pad): + def __init__(self, pad, pad_n=None): self.o = Signal(8) self.i = Signal(8) self.oe = Signal() @@ -47,9 +54,14 @@ class _IOSERDESE2_8X(Module): i_CLKDIV=ClockSignal("rio_phy")) oserdes = _OSERDESE2_8X(pad_o) self.submodules += oserdes - self.specials += Instance("IOBUF", - i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, - io_IO=pad) + if pad_n is None: + self.specials += Instance("IOBUF", + i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, + io_IO=pad) + else: + self.specials += Instance("IOBUFDS", + i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, + io_IO=pad, io_IOB=pad_n) self.comb += [ oserdes.t_in.eq(~self.oe), oserdes.o.eq(self.o) @@ -57,14 +69,14 @@ class _IOSERDESE2_8X(Module): class Output_8X(ttl_serdes_generic.Output): - def __init__(self, pad): - serdes = _OSERDESE2_8X(pad) + def __init__(self, pad, pad_n=None): + serdes = _OSERDESE2_8X(pad, pad_n) self.submodules += serdes ttl_serdes_generic.Output.__init__(self, serdes) class Inout_8X(ttl_serdes_generic.Inout): - def __init__(self, pad): - serdes = _IOSERDESE2_8X(pad) + def __init__(self, pad, pad_n=None): + serdes = _IOSERDESE2_8X(pad, pad_n) self.submodules += serdes ttl_serdes_generic.Inout.__init__(self, serdes) From a91ed8394c2964bc335747f92a0ece5486b8009a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 1 Oct 2016 02:36:03 +0200 Subject: [PATCH 002/157] rtio: add input-only channel --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index 018762984..846cc6fc3 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -31,6 +31,32 @@ class _OSERDESE2_8X(Module): o_O=pad, o_OB=pad_n) +class _ISERDESE2_8X(Module): + def __init__(self, pad, pad_n=None): + self.o = Signal(8) + self.i = Signal(8) + self.oe = Signal() + + # # # + + pad_i = Signal() + i = self.i + self.specials += Instance("ISERDESE2", p_DATA_RATE="DDR", + p_DATA_WIDTH=8, + p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, + o_Q1=i[7], o_Q2=i[6], o_Q3=i[5], o_Q4=i[4], + o_Q5=i[3], o_Q6=i[2], o_Q7=i[1], o_Q8=i[0], + i_D=pad_i, + i_CLK=ClockSignal("rtiox4"), + i_CLKB=~ClockSignal("rtiox4"), + i_CE1=1, i_RST=0, + i_CLKDIV=ClockSignal("rio_phy")) + if pad_n is None: + self.comb += pad_i.eq(pad) + else: + self.specials += Instance("IBUFDS", o_O=pad_i, i_I=pad, i_IB=pad_n) + + class _IOSERDESE2_8X(Module): def __init__(self, pad, pad_n=None): self.o = Signal(8) @@ -80,3 +106,9 @@ class Inout_8X(ttl_serdes_generic.Inout): serdes = _IOSERDESE2_8X(pad, pad_n) self.submodules += serdes ttl_serdes_generic.Inout.__init__(self, serdes) + +class Input_8X(ttl_serdes_generic.Inout): + def __init__(self, pad, pad_n=None): + serdes = _ISERDESE2_8X(pad, pad_n) + self.submodules += serdes + ttl_serdes_generic.Inout.__init__(self, serdes) From 2bc5dc4ecb5935a24a6040fec9d049ac3450f024 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Sep 2016 21:54:24 +0200 Subject: [PATCH 003/157] i2c: cleanup includes --- artiq/runtime/i2c.c | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/runtime/i2c.c b/artiq/runtime/i2c.c index c8ec3f131..136df4303 100644 --- a/artiq/runtime/i2c.c +++ b/artiq/runtime/i2c.c @@ -1,7 +1,6 @@ #include #include "artiq_personality.h" -#include "rtio.h" #include "i2c.h" From 4a0eaf0f95af467576e210afc316d417a3c0f448 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 22 Jul 2016 15:56:09 +0200 Subject: [PATCH 004/157] phaser: add jesd204b rtio dds gateware: add jesd204b awg gateware: copy phaser (df3825a) dsp/tools: update satadd mixin phaser: no DDS stubs dsp: accu fix phaser: cleanup/reduce sawg: kernel support and docs sawg: coredevice api fixes sawg: example ddb/experiment phaser: add conda package examples/phaser: typo sawg: adapt tests, fix accu stb sawg: tweak dds parameters sawg: move/adapt/extend tests sawg: test phy, refactor phaser: non-rtio spi phaser: target cli update phaser: ad9154-fmc-ebz pins phaser: reorganize fmc signal naming phaser: add test mode stubs phaser: txen is LVTTL phaser: clk spi xfer test phaser: spi for ad9154 and ad9516 phaser: spi tweaks ad9154: add register map from ad9144.xml ad9516: add register map from ad9517.xml and manual adaptation ad9154_reg: just generate getter/setter macros as well ad9154: reg WIP ad9154: check and fix registers kc705: single ended rtio_external_clk use single ended user_sma_clk_n instead of p/n to free up one clock sma kc705: mirror clk200 at user_sma_clock_p ad9516_regs.h: fix B_COUNTER_MSB phase: wire up clocking differently needs patched misoc kc705: feed rtio_external_clock directly kc705: remove rtio_external_clk for phaser phaser: spi tweaks ad9516: some startup ad9516_reg fixes phaser: setup ad9516 for supposed 500 MHz operation ad9516: use full duplex spi ad9154_reg: add CONFIG_REG_2 ad9154_reg: fixes phaser: write some ad9154 config ad9154_reg: fixes ad9154: more init, and human readable setup ad9154/ad9516: merge spi support ad9154: status readout Revert "kc705: remove rtio_external_clk for phaser" This reverts commit d500288bb44f2bf2eeb0c2f237aa207b0a8b1366. Revert "kc705: feed rtio_external_clock directly" This reverts commit 8dc7825519e3e75b7d3d29c9abf10fc6e3a8b4c5. Revert "phase: wire up clocking differently" This reverts commit ad9cc450ffa35abb54b0842d56f6cf6c53c6fbcc. Revert "kc705: mirror clk200 at user_sma_clock_p" This reverts commit 7f0dffdcdd28e648af84725682f82ec6e5642eba. Revert "kc705: single ended rtio_external_clk" This reverts commit a9426d983fbf5c1cb768da8f1da26d9b7335e9cf. ad9516: 2000 MHz clock phaser: test clock dist phaser: test freqs ad9154: iostandards phaser: drop clock monitor phaser: no separate i2c phaser: drive rtio from refclk, wire up sysref phaser: ttl channel for sync ad9154: 4x interp, status, tweaks phaser: sync/sysref 33V banks phaser: sync/sysref LVDS_25 inputs are VCCO tolerant phaser: user input-only ttls phaser: rtio fully from refclk ad9154: reg name usage fix ad9154: check register modifications Revert "ad9154: check register modifications" This reverts commit 45121d90edf89f7bd8703503f9f317ad050f9564. ad9154: fix status code ad9154: addrinc, recal serdes pll phaser: coredevice, example tweaks sawg: missing import sawg: type fixes ad9514: move setup functions ad9154: msb first also decreasing addr phaser: use sys4x for rtio internal ref phaser: move init code to main phaser: naming cleanup phaser: cleanup pins phaser: move spi to kernel cpu phaser: kernel support for ad9154 spi ad9154: add r/w methods ad9154: need return annotations ad9154: r/w methods are kernels ad9154_reg: portable helpers phaser: cleanup startup kernel ad9154: status test ad9154: prbs test ad9154: move setup, document phaser: more documentation --- artiq/coredevice/ad9154.py | 68 + artiq/coredevice/ad9154_reg.py | 2980 +++++++++++++++++ artiq/coredevice/ad9516_reg.py | 291 ++ artiq/coredevice/sawg.py | 73 + artiq/examples/phaser/device_db.pyon | 77 + artiq/examples/phaser/idle_kernel.py | 21 + artiq/examples/phaser/repository/sawg.py | 34 + .../phaser/repository/test_ad9154_prbs.py | 46 + .../phaser/repository/test_ad9154_status.py | 126 + artiq/examples/phaser/startup_kernel.py | 306 ++ artiq/gateware/dsp/__init__.py | 0 artiq/gateware/dsp/accu.py | 112 + artiq/gateware/dsp/cordic.py | 358 ++ artiq/gateware/dsp/sawg.py | 67 + artiq/gateware/dsp/tools.py | 50 + artiq/gateware/phaser.py | 71 + artiq/gateware/rtio/phy/sawg.py | 27 + artiq/gateware/targets/kc705.py | 144 +- artiq/runtime/Makefile | 2 +- artiq/runtime/ad9154.c | 57 + artiq/runtime/ad9154.h | 14 + artiq/runtime/ksupport.c | 9 + artiq/runtime/main.c | 1 + artiq/test/gateware/__init__.py | 0 artiq/test/gateware/test_accu.py | 46 + artiq/test/gateware/test_sawg.py | 34 + artiq/test/gateware/test_sawg_phy.py | 61 + conda/artiq-kc705-phaser/build.sh | 14 + conda/artiq-kc705-phaser/meta.yaml | 27 + doc/manual/core_device.rst | 32 + doc/manual/core_drivers_reference.rst | 12 + doc/manual/installing.rst | 1 + 32 files changed, 5155 insertions(+), 6 deletions(-) create mode 100644 artiq/coredevice/ad9154.py create mode 100644 artiq/coredevice/ad9154_reg.py create mode 100644 artiq/coredevice/ad9516_reg.py create mode 100644 artiq/coredevice/sawg.py create mode 100644 artiq/examples/phaser/device_db.pyon create mode 100644 artiq/examples/phaser/idle_kernel.py create mode 100644 artiq/examples/phaser/repository/sawg.py create mode 100644 artiq/examples/phaser/repository/test_ad9154_prbs.py create mode 100644 artiq/examples/phaser/repository/test_ad9154_status.py create mode 100644 artiq/examples/phaser/startup_kernel.py create mode 100644 artiq/gateware/dsp/__init__.py create mode 100644 artiq/gateware/dsp/accu.py create mode 100644 artiq/gateware/dsp/cordic.py create mode 100644 artiq/gateware/dsp/sawg.py create mode 100644 artiq/gateware/dsp/tools.py create mode 100644 artiq/gateware/phaser.py create mode 100644 artiq/gateware/rtio/phy/sawg.py create mode 100644 artiq/runtime/ad9154.c create mode 100644 artiq/runtime/ad9154.h create mode 100644 artiq/test/gateware/__init__.py create mode 100644 artiq/test/gateware/test_accu.py create mode 100644 artiq/test/gateware/test_sawg.py create mode 100644 artiq/test/gateware/test_sawg_phy.py create mode 100644 conda/artiq-kc705-phaser/build.sh create mode 100644 conda/artiq-kc705-phaser/meta.yaml diff --git a/artiq/coredevice/ad9154.py b/artiq/coredevice/ad9154.py new file mode 100644 index 000000000..d13fb4a2e --- /dev/null +++ b/artiq/coredevice/ad9154.py @@ -0,0 +1,68 @@ +from artiq.language.core import kernel, syscall +from artiq.language.types import TInt32, TNone + + +@syscall(flags={"nounwind", "nowrite"}) +def ad9154_init() -> TNone: + raise NotImplementedError("syscall not simulated") + + +@syscall(flags={"nounwind", "nowrite"}) +def ad9154_write(addr: TInt32, data: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + + +@syscall(flags={"nounwind", "nowrite"}) +def ad9154_read(addr: TInt32) -> TInt32: + raise NotImplementedError("syscall not simulated") + + +@syscall(flags={"nounwind", "nowrite"}) +def ad9516_write(addr: TInt32, data: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + + +@syscall(flags={"nounwind", "nowrite"}) +def ad9516_read(addr: TInt32) -> TInt32: + raise NotImplementedError("syscall not simulated") + + +class AD9154: + """AD9154-FMC-EBZ SPI support + + There are two devices on the SPI bus, a AD9154 DAC and a AD9516 clock + divider/fanout. + + Register and bit names are in :mod:`artiq.coredevice.ad9154_reg` and + :mod:`artiq.coredevice.ad9516_reg` respectively. + + The SPI bus does not operate over RTIO but directly. This class does not + interact with the timeline. + """ + def __init__(self, dmgr, core_device="core"): + self.core = dmgr.get(core_device) + + @kernel + def init(self): + """Initialize and configure the SPI bus.""" + ad9154_init() + + @kernel + def dac_write(self, addr, data): + """Write `data` to AD9154 SPI register at `addr`.""" + ad9154_write(addr, data) + + @kernel + def dac_read(self, addr): + """Read AD9154 SPI register at `addr`.""" + return ad9154_read(addr) + + @kernel + def clock_write(self, addr, data): + """Write `data` to AD9516 SPI register at `addr`.""" + ad9516_write(addr, data) + + @kernel + def clock_read(self, addr): + """Read AD9516 SPI register at `addr`.""" + return ad9516_read(addr) diff --git a/artiq/coredevice/ad9154_reg.py b/artiq/coredevice/ad9154_reg.py new file mode 100644 index 000000000..1f51d7315 --- /dev/null +++ b/artiq/coredevice/ad9154_reg.py @@ -0,0 +1,2980 @@ +# auto-generated, do not edit +from artiq.language.core import portable +from artiq.language.types import TInt32 + +AD9154_SPI_INTFCONFA = 0x000 +# default: 0x00, access: R/W +@portable +def AD9154_SOFTRESET_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_SOFTRESET_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_LSBFIRST_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_LSBFIRST_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_ADDRINC_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_ADDRINC_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SDOACTIVE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_SDOACTIVE_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SDOACTIVE_M_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_ADDRINC_M_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_LSBFIRST_M_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SOFTRESET_M_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_CHIPTYPE = 0x003 + +AD9154_PRODIDL = 0x004 + +AD9154_PRODIDH = 0x005 + +AD9154_CHIPGRADE = 0x006 +# default: 0x02, access: R +@portable +def AD9154_DEV_REVISION_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x00, access: R +@portable +def AD9154_PROD_GRADE_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0xf + + +AD9154_SPI_PAGEINDX = 0x008 + +AD9154_PWRCNTRL0 = 0x011 +# default: 0x01, access: R/W +@portable +def AD9154_PD_DAC3_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_PD_DAC3_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_PD_DAC2_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_PD_DAC2_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_PD_DAC1_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_PD_DAC1_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_PD_DAC0_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_PD_DAC0_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_PD_BG_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_PD_BG_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_TXENMASK1 = 0x012 +# default: 0x00, access: R/W +@portable +def AD9154_DACA_MASK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_DACA_MASK_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_DACB_MASK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_DACB_MASK_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_PWRCNTRL3 = 0x013 +# default: 0x00, access: R/W +@portable +def AD9154_SPI_TXEN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_SPI_TXEN_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_ENA_SPI_TXEN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_ENA_SPI_TXEN_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_PA_CTRL_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_SPI_PA_CTRL_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_ENA_PA_CTRL_FROM_SPI_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_ENA_PA_CTRL_FROM_SPI_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_ENA_PA_CTRL_FROM_BLSM_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_ENA_PA_CTRL_FROM_BLSM_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_ENA_PA_CTRL_FROM_TXENSM_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_ENA_PA_CTRL_FROM_TXENSM_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_ENA_PA_CTRL_FROM_PARROT_ERR_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_ENA_PA_CTRL_FROM_PARROT_ERR_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + + +AD9154_GROUP_DLY = 0x014 +# default: 0x08, access: R/W +@portable +def AD9154_COARSE_GROUP_DELAY_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 0 + +@portable +def AD9154_COARSE_GROUP_DELAY_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x08, access: R/W +@portable +def AD9154_GROUP_DELAY_RESERVED_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 4 + +@portable +def AD9154_GROUP_DELAY_RESERVED_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0xf + + +AD9154_IRQEN_STATUSMODE0 = 0x01f +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_LANEFIFOERR_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_IRQEN_SMODE_LANEFIFOERR_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_SERPLLLOCK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_IRQEN_SMODE_SERPLLLOCK_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_SERPLLLOST_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_IRQEN_SMODE_SERPLLLOST_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_DACPLLLOCK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_IRQEN_SMODE_DACPLLLOCK_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_DACPLLLOST_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_IRQEN_SMODE_DACPLLLOST_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + + +AD9154_IRQEN_STATUSMODE1 = 0x020 +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_PRBS0_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_IRQEN_SMODE_PRBS0_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_PRBS1_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_IRQEN_SMODE_PRBS1_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_PRBS2_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_IRQEN_SMODE_PRBS2_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_PRBS3_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_IRQEN_SMODE_PRBS3_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + + +AD9154_IRQEN_STATUSMODE2 = 0x021 +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_SYNC_TRIP0_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_IRQEN_SMODE_SYNC_TRIP0_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_SYNC_WLIM0_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_IRQEN_SMODE_SYNC_WLIM0_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_SYNC_ROTATE0_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_IRQEN_SMODE_SYNC_ROTATE0_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_SYNC_LOCK0_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_IRQEN_SMODE_SYNC_LOCK0_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_NCO_ALIGN0_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_IRQEN_SMODE_NCO_ALIGN0_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_BLNKDONE0_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_IRQEN_SMODE_BLNKDONE0_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_PDPERR0_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_IRQEN_SMODE_PDPERR0_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_IRQEN_STATUSMODE3 = 0x022 +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_SYNC_TRIP1_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_IRQEN_SMODE_SYNC_TRIP1_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_SYNC_WLIM1_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_IRQEN_SMODE_SYNC_WLIM1_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_SYNC_ROTATE1_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_IRQEN_SMODE_SYNC_ROTATE1_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_SYNC_LOCK1_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_IRQEN_SMODE_SYNC_LOCK1_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_NCO_ALIGN1_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_IRQEN_SMODE_NCO_ALIGN1_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_BLNKDONE1_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_IRQEN_SMODE_BLNKDONE1_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_IRQEN_SMODE_PDPERR1_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_IRQEN_SMODE_PDPERR1_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_IRQ_STATUS0 = 0x023 +# default: 0x00, access: R +@portable +def AD9154_LANEFIFOERR_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SERPLLLOCK_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SERPLLLOST_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_DACPLLLOCK_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_DACPLLLOST_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + + +AD9154_IRQ_STATUS1 = 0x024 +# default: 0x00, access: R +@portable +def AD9154_PRBS0_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_PRBS1_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_PRBS2_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_PRBS3_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + + +AD9154_IRQ_STATUS2 = 0x025 +# default: 0x00, access: R +@portable +def AD9154_SYNC_TRIP0_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SYNC_WLIM0_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SYNC_ROTATE0_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SYNC_LOCK0_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_NCO_ALIGN0_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_BLNKDONE0_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_PDPERR0_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_IRQ_STATUS3 = 0x026 +# default: 0x00, access: R +@portable +def AD9154_SYNC_TRIP1_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SYNC_WLIM1_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SYNC_ROTATE1_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SYNC_LOCK1_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_NCO_ALIGN1_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_BLNKDONE1_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_PDPERR1_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_JESD_CHECKS = 0x030 +# default: 0x00, access: R +@portable +def AD9154_ERR_INTSUPP_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_ERR_SUBCLASS_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_ERR_KUNSUPP_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_ERR_JESDBAD_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_ERR_WINLIMIT_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_ERR_DLYOVER_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + + +AD9154_SYNC_ERRWINDOW = 0x034 + +AD9154_SYNC_LASTERR_L = 0x038 + +AD9154_SYNC_LASTERR_H = 0x039 +# default: 0x00, access: R +@portable +def AD9154_LASTERROR_H_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_LASTOVER_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_LASTUNDER_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_SYNC_CONTROL = 0x03a +# default: 0x00, access: R/W +@portable +def AD9154_SYNCMODE_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 0 + +@portable +def AD9154_SYNCMODE_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x00, access: R/W +@portable +def AD9154_SYNCCLRLAST_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_SYNCCLRLAST_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SYNCCLRSTKY_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_SYNCCLRSTKY_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SYNCARM_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_SYNCARM_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SYNCENABLE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_SYNCENABLE_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_SYNC_STATUS = 0x03b +# default: 0x00, access: R +@portable +def AD9154_SYNC_TRIP_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SYNC_WLIM_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SYNC_ROTATE_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SYNC_LOCK_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SYNC_BUSY_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_SYNC_CURRERR_L = 0x03c + +AD9154_SYNC_CURRERR_H = 0x03d +# default: 0x00, access: R +@portable +def AD9154_CURRERROR_H_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_CURROVER_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_CURRUNDER_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_DACGAIN0_I = 0x040 + +AD9154_DACGAIN1_I = 0x041 + +AD9154_DACGAIN0_Q = 0x042 + +AD9154_DACGAIN1_Q = 0x043 + +AD9154_GROUPDELAY_COMP_I = 0x044 + +AD9154_GROUPDELAY_COMP_Q = 0x045 + +AD9154_GROUPDELAY_COMP_BYP = 0x046 +# default: 0x01, access: R/W +@portable +def AD9154_GROUPCOMP_BYPQ_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_GROUPCOMP_BYPQ_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_GROUPCOMP_BYPI_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_GROUPCOMP_BYPI_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + + +AD9154_MIX_MODE = 0x047 + +AD9154_NCOALIGN_MODE = 0x050 +# default: 0x00, access: R/W +@portable +def AD9154_NCO_ALIGN_MODE_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 0 + +@portable +def AD9154_NCO_ALIGN_MODE_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3 + +# default: 0x00, access: R +@portable +def AD9154_NCO_ALIGN_FAIL_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_NCO_ALIGN_PASS_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_NCO_ALIGN_MTCH_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_NCO_ALIGN_ARM_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_NCO_ALIGN_ARM_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_NCOKEY_ILSB = 0x051 + +AD9154_NCOKEY_IMSB = 0x052 + +AD9154_NCOKEY_QLSB = 0x053 + +AD9154_NCOKEY_QMSB = 0x054 + +AD9154_PDP_THRES0 = 0x060 + +AD9154_PDP_THRES1 = 0x061 + +AD9154_PDP_AVG_TIME = 0x062 +# default: 0x00, access: R/W +@portable +def AD9154_PDP_AVG_TIME__SET(x: TInt32) -> TInt32: + return (x & 0xf) << 0 + +@portable +def AD9154_PDP_AVG_TIME__GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x00, access: R/W +@portable +def AD9154_PA_BUS_SWAP_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_PA_BUS_SWAP_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_PDP_ENABLE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_PDP_ENABLE_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_PDP_POWER0 = 0x063 + +AD9154_PDP_POWER1 = 0x064 + +AD9154_CLKCFG0 = 0x080 +# default: 0x00, access: R/W +@portable +def AD9154_REF_CLKDIV_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_REF_CLKDIV_EN_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_RF_SYNC_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_RF_SYNC_EN_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_DUTY_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_DUTY_EN_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_PD_CLK_REC_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_PD_CLK_REC_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_PD_SERDES_PCLK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_PD_SERDES_PCLK_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_PD_CLK_DIG_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_PD_CLK_DIG_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_PD_CLK23_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_PD_CLK23_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_PD_CLK01_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_PD_CLK01_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_SYSREF_ACTRL0 = 0x081 +# default: 0x00, access: R/W +@portable +def AD9154_HYS_CNTRL1_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 0 + +@portable +def AD9154_HYS_CNTRL1_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3 + +# default: 0x00, access: R/W +@portable +def AD9154_SYSREF_RISE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_SYSREF_RISE_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_HYS_ON_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_HYS_ON_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_PD_SYSREF_BUFFER_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_PD_SYSREF_BUFFER_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + + +AD9154_SYSREF_ACTRL1 = 0x082 + +AD9154_DACPLLCNTRL = 0x083 +# default: 0x00, access: R/W +@portable +def AD9154_ENABLE_DACPLL_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_ENABLE_DACPLL_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_RECAL_DACPLL_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_RECAL_DACPLL_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_DACPLLSTATUS = 0x084 +# default: 0x00, access: R +@portable +def AD9154_DACPLL_LOCK_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_VCO_CAL_PROGRESS_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_CP_CAL_VALID_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_CP_OVERRANGE_L_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_CP_OVERRANGE_H_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x3 + + +AD9154_DACINTEGERWORD0 = 0x085 + +AD9154_DACLOOPFILT1 = 0x087 +# default: 0x08, access: R/W +@portable +def AD9154_LF_C1_WORD_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 0 + +@portable +def AD9154_LF_C1_WORD_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x08, access: R/W +@portable +def AD9154_LF_C2_WORD_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 4 + +@portable +def AD9154_LF_C2_WORD_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0xf + + +AD9154_DACLOOPFILT2 = 0x088 +# default: 0x08, access: R/W +@portable +def AD9154_LF_C3_WORD_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 0 + +@portable +def AD9154_LF_C3_WORD_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x08, access: R/W +@portable +def AD9154_LF_R1_WORD_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 4 + +@portable +def AD9154_LF_R1_WORD_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0xf + + +AD9154_DACLOOPFILT3 = 0x089 +# default: 0x08, access: R/W +@portable +def AD9154_LF_R3_WORD_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 0 + +@portable +def AD9154_LF_R3_WORD_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x00, access: R/W +@portable +def AD9154_LF_BYPASS_C1_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_LF_BYPASS_C1_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_LF_BYPASS_C2_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_LF_BYPASS_C2_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_LF_BYPASS_R1_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_LF_BYPASS_R1_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_LF_BYPASS_R3_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_LF_BYPASS_R3_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_DACCPCNTRL = 0x08a +# default: 0x20, access: R/W +@portable +def AD9154_CP_CURRENT_SET(x: TInt32) -> TInt32: + return (x & 0x3f) << 0 + +@portable +def AD9154_CP_CURRENT_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3f + +# default: 0x00, access: R/W +@portable +def AD9154_VT_FORCE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_VT_FORCE_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + + +AD9154_DACLOGENCNTRL = 0x08b +# default: 0x00, access: R/W +@portable +def AD9154_LODIVMODE_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 0 + +@portable +def AD9154_LODIVMODE_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3 + +# default: 0x00, access: R/W +@portable +def AD9154_LO_POWER_MODE_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 4 + +@portable +def AD9154_LO_POWER_MODE_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x3 + + +AD9154_DACLDOCNTRL1 = 0x08c +# default: 0x00, access: R/W +@portable +def AD9154_REFDIVMODE_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 0 + +@portable +def AD9154_REFDIVMODE_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x7 + +# default: 0x00, access: R/W +@portable +def AD9154_LDO_BYPASS_FLT_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_LDO_BYPASS_FLT_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_LDO_REF_SEL_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_LDO_REF_SEL_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_DACLDOCNTRL2 = 0x08d +# default: 0x03, access: R/W +@portable +def AD9154_LDO_VDROP_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 0 + +@portable +def AD9154_LDO_VDROP_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3 + +# default: 0x02, access: R/W +@portable +def AD9154_LDO_SEL_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 2 + +@portable +def AD9154_LDO_SEL_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x7 + +# default: 0x01, access: R/W +@portable +def AD9154_LDO_INRUSH_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 5 + +@portable +def AD9154_LDO_INRUSH_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x3 + +# default: 0x00, access: R/W +@portable +def AD9154_LDO_BYPASS_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_LDO_BYPASS_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_DATA_FORMAT = 0x110 +# default: 0x00, access: R/W +@portable +def AD9154_BINARY_FORMAT_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_BINARY_FORMAT_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_DATAPATH_CTRL = 0x111 +# default: 0x00, access: R/W +@portable +def AD9154_I_TO_Q_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_I_TO_Q_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SEL_SIDEBAND_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_SEL_SIDEBAND_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_MODULATION_TYPE_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 2 + +@portable +def AD9154_MODULATION_TYPE_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x3 + +# default: 0x00, access: R/W +@portable +def AD9154_PHASE_ADJ_ENABLE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_PHASE_ADJ_ENABLE_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_DIG_GAIN_ENABLE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_DIG_GAIN_ENABLE_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_INVSINC_ENABLE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_INVSINC_ENABLE_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_INTERP_MODE = 0x112 + +AD9154_NCO_FTW_UPDATE = 0x113 +# default: 0x00, access: R/W +@portable +def AD9154_FTW_UPDATE_REQ_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_FTW_UPDATE_REQ_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_FTW_UPDATE_ACK_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + + +AD9154_FTW0 = 0x114 + +AD9154_FTW1 = 0x115 + +AD9154_FTW2 = 0x116 + +AD9154_FTW3 = 0x117 + +AD9154_FTW4 = 0x118 + +AD9154_FTW5 = 0x119 + +AD9154_NCO_PHASE_OFFSET0 = 0x11a + +AD9154_NCO_PHASE_OFFSET1 = 0x11b + +AD9154_PHASE_ADJ0 = 0x11c + +AD9154_PHASE_ADJ1 = 0x11d + +AD9154_TXEN_SM_0 = 0x11f +# default: 0x01, access: R/W +@portable +def AD9154_TXEN_SM_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_TXEN_SM_EN_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_GP_PA_CTRL_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_GP_PA_CTRL_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_GP_PA_ON_INVERT_SET(x: TInt32) -> TInt32: + return (x & 0x0) << 2 + +@portable +def AD9154_GP_PA_ON_INVERT_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x0 + +# default: 0x00, access: R/W +@portable +def AD9154_RISE_COUNTERS_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 4 + +@portable +def AD9154_RISE_COUNTERS_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x3 + +# default: 0x02, access: R/W +@portable +def AD9154_FALL_COUNTERS_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 6 + +@portable +def AD9154_FALL_COUNTERS_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x3 + + +AD9154_TXEN_RISE_COUNT_0 = 0x121 + +AD9154_TXEN_RISE_COUNT_1 = 0x122 + +AD9154_TXEN_FALL_COUNT_0 = 0x123 + +AD9154_TXEN_FALL_COUNT_1 = 0x124 + +AD9154_DEVICE_CONFIG_REG_0 = 0x12d + +AD9154_DIE_TEMP_CTRL0 = 0x12f +# default: 0x00, access: R/W +@portable +def AD9154_AUXADC_ENABLE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_AUXADC_ENABLE_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x10, access: R/W +@portable +def AD9154_AUXADC_RESERVED_SET(x: TInt32) -> TInt32: + return (x & 0x7f) << 1 + +@portable +def AD9154_AUXADC_RESERVED_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x7f + + +AD9154_DIE_TEMP0 = 0x132 + +AD9154_DIE_TEMP1 = 0x133 + +AD9154_DIE_TEMP_UPDATE = 0x134 + +AD9154_DC_OFFSET_CTRL = 0x135 + +AD9154_IPATH_DC_OFFSET_1PART0 = 0x136 + +AD9154_IPATH_DC_OFFSET_1PART1 = 0x137 + +AD9154_QPATH_DC_OFFSET_1PART0 = 0x138 + +AD9154_QPATH_DC_OFFSET_1PART1 = 0x139 + +AD9154_IPATH_DC_OFFSET_2PART = 0x13a + +AD9154_QPATH_DC_OFFSET_2PART = 0x13b + +AD9154_IDAC_DIG_GAIN0 = 0x13c + +AD9154_IDAC_DIG_GAIN1 = 0x13d + +AD9154_QDAC_DIG_GAIN0 = 0x13e + +AD9154_QDAC_DIG_GAIN1 = 0x13f + +AD9154_GAIN_RAMP_UP_STEP0 = 0x140 + +AD9154_GAIN_RAMP_UP_STEP1 = 0x141 + +AD9154_GAIN_RAMP_DOWN_STEP0 = 0x142 + +AD9154_GAIN_RAMP_DOWN_STEP1 = 0x143 + +AD9154_DEVICE_CONFIG_REG_1 = 0x146 + +AD9154_BSM_STAT = 0x147 +# default: 0x00, access: R +@portable +def AD9154_SOFTBLANKRB_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x3 + + +AD9154_PRBS = 0x14b +# default: 0x00, access: R/W +@portable +def AD9154_PRBS_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_PRBS_EN_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_PRBS_RESET_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_PRBS_RESET_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_PRBS_MODE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_PRBS_MODE_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_PRBS_GOOD_I_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_PRBS_GOOD_Q_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_PRBS_ERROR_I = 0x14c + +AD9154_PRBS_ERROR_Q = 0x14d + +AD9154_DACPLLT0 = 0x1b0 +# default: 0x01, access: R/W +@portable +def AD9154_LOGEN_PD_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_LOGEN_PD_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_LDO_PD_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_LDO_PD_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_SYNTH_PD_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_SYNTH_PD_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_VCO_PD_ALC_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_VCO_PD_ALC_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_VCO_PD_PTAT_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_VCO_PD_PTAT_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_VCO_PD_IN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_VCO_PD_IN_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_DACPLLT1 = 0x1b1 +# default: 0x00, access: R/W +@portable +def AD9154_PFD_EDGE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_PFD_EDGE_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_PFD_DELAY_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 2 + +@portable +def AD9154_PFD_DELAY_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x3 + + +AD9154_DACPLLT2 = 0x1b2 +# default: 0x00, access: R/W +@portable +def AD9154_EXT_ALC_WORD_SET(x: TInt32) -> TInt32: + return (x & 0x7f) << 0 + +@portable +def AD9154_EXT_ALC_WORD_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x7f + +# default: 0x00, access: R/W +@portable +def AD9154_EXT_ALC_WORD_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_EXT_ALC_WORD_EN_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_DACPLLT3 = 0x1b3 +# default: 0x00, access: W +@portable +def AD9154_EXT_BAND1_SET(x: TInt32) -> TInt32: + return (x & 0xff) << 0 + + +AD9154_DACPLLT4 = 0x1b4 +# default: 0x00, access: R/W +@portable +def AD9154_EXT_BAND2_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_EXT_BAND2_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_EXT_BAND_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_EXT_BAND_EN_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x0f, access: R/W +@portable +def AD9154_VCO_CAL_OFFSET_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 3 + +@portable +def AD9154_VCO_CAL_OFFSET_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0xf + +# default: 0x00, access: R/W +@portable +def AD9154_BYP_LOAD_DELAY_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_BYP_LOAD_DELAY_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_DACPLLT5 = 0x1b5 + +AD9154_DACPLLT6 = 0x1b6 + +AD9154_DACPLLT7 = 0x1b7 + +AD9154_DACPLLT8 = 0x1b8 + +AD9154_DACPLLT9 = 0x1b9 + +AD9154_DACPLLTA = 0x1ba + +AD9154_DACPLLTB = 0x1bb +# default: 0x04, access: R/W +@portable +def AD9154_VCO_BIAS_REF_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 0 + +@portable +def AD9154_VCO_BIAS_REF_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x7 + +# default: 0x01, access: R/W +@portable +def AD9154_VCO_BIAS_TCF_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 3 + +@portable +def AD9154_VCO_BIAS_TCF_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x3 + + +AD9154_DACPLLTC = 0x1bc + +AD9154_DACPLLTD = 0x1bd + +AD9154_DACPLLTE = 0x1be + +AD9154_DACPLLTF = 0x1bf + +AD9154_DACPLLT10 = 0x1c0 + +AD9154_DACPLLT11 = 0x1c1 + +AD9154_DACPLLT15 = 0x1c2 + +AD9154_DACPLLT16 = 0x1c3 + +AD9154_DACPLLT17 = 0x1c4 + +AD9154_DACPLLT18 = 0x1c5 + +AD9154_MASTER_PD = 0x200 + +AD9154_PHY_PD = 0x201 + +AD9154_GENERIC_PD = 0x203 +# default: 0x00, access: R/W +@portable +def AD9154_PD_SYNCOUT1B_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_PD_SYNCOUT1B_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_PD_SYNCOUT0B_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_PD_SYNCOUT0B_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + + +AD9154_CDR_RESET = 0x206 + +AD9154_CDR_OPERATING_MODE_REG_0 = 0x230 +# default: 0x00, access: R/W +@portable +def AD9154_CDR_OVERSAMP_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_CDR_OVERSAMP_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x02, access: R/W +@portable +def AD9154_CDR_RESERVED_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 2 + +@portable +def AD9154_CDR_RESERVED_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x7 + +# default: 0x01, access: R/W +@portable +def AD9154_ENHALFRATE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_ENHALFRATE_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + + +AD9154_EQ_BIAS_REG = 0x268 +# default: 0x22, access: R/W +@portable +def AD9154_EQ_BIAS_RESERVED_SET(x: TInt32) -> TInt32: + return (x & 0x3f) << 0 + +@portable +def AD9154_EQ_BIAS_RESERVED_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3f + +# default: 0x01, access: R/W +@portable +def AD9154_EQ_POWER_MODE_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 6 + +@portable +def AD9154_EQ_POWER_MODE_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x3 + + +AD9154_SERDESPLL_ENABLE_CNTRL = 0x280 +# default: 0x00, access: R/W +@portable +def AD9154_ENABLE_SERDESPLL_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_ENABLE_SERDESPLL_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_RECAL_SERDESPLL_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_RECAL_SERDESPLL_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + + +AD9154_PLL_STATUS = 0x281 +# default: 0x00, access: R +@portable +def AD9154_SERDES_PLL_LOCK_RB_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SERDES_CURRENTS_READY_RB_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SERDES_VCO_CAL_IN_PROGRESS_RB_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SERDES_PLL_CAL_VALID_RB_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SERDES_PLL_OVERRANGE_L_RB_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_SERDES_PLL_OVERRANGE_H_RB_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + + +AD9154_LDO_FILTER_1 = 0x284 + +AD9154_LDO_FILTER_2 = 0x285 + +AD9154_LDO_FILTER_3 = 0x286 + +AD9154_CP_CURRENT_SPI = 0x287 +# default: 0x3f, access: R/W +@portable +def AD9154_SPI_CP_CURRENT_SET(x: TInt32) -> TInt32: + return (x & 0x3f) << 0 + +@portable +def AD9154_SPI_CP_CURRENT_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3f + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_SERDES_LOGEN_POWER_MODE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_SPI_SERDES_LOGEN_POWER_MODE_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + + +AD9154_REF_CLK_DIVIDER_LDO = 0x289 +# default: 0x00, access: R/W +@portable +def AD9154_SPI_CDR_OVERSAMP_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 0 + +@portable +def AD9154_SPI_CDR_OVERSAMP_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3 + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_LDO_BYPASS_FILT_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_SPI_LDO_BYPASS_FILT_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_LDO_REF_SEL_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_SPI_LDO_REF_SEL_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + + +AD9154_VCO_LDO = 0x28a + +AD9154_PLL_RD_REG = 0x28b +# default: 0x01, access: R/W +@portable +def AD9154_SPI_SERDES_LOGEN_PD_CORE_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 0 + +@portable +def AD9154_SPI_SERDES_LOGEN_PD_CORE_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3 + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_SERDES_LDO_PD_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_SPI_SERDES_LDO_PD_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_SYN_PD_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_SPI_SYN_PD_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_VCO_PD_ALC_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_SPI_VCO_PD_ALC_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_VCO_PD_PTAT_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_SPI_VCO_PD_PTAT_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_VCO_PD_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_SPI_VCO_PD_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + + +AD9154_ALC_VARACTOR = 0x290 +# default: 0x03, access: R/W +@portable +def AD9154_SPI_VCO_VARACTOR_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 0 + +@portable +def AD9154_SPI_VCO_VARACTOR_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x08, access: R/W +@portable +def AD9154_SPI_INIT_ALC_VALUE_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 4 + +@portable +def AD9154_SPI_INIT_ALC_VALUE_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0xf + + +AD9154_VCO_OUTPUT = 0x291 +# default: 0x09, access: R/W +@portable +def AD9154_SPI_VCO_OUTPUT_LEVEL_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 0 + +@portable +def AD9154_SPI_VCO_OUTPUT_LEVEL_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x04, access: R/W +@portable +def AD9154_SPI_VCO_OUTPUT_RESERVED_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 4 + +@portable +def AD9154_SPI_VCO_OUTPUT_RESERVED_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0xf + + +AD9154_CP_CONFIG = 0x294 +# default: 0x00, access: R/W +@portable +def AD9154_SPI_CP_TEST_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 0 + +@portable +def AD9154_SPI_CP_TEST_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_CP_CAL_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_SPI_CP_CAL_EN_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_CP_FORCE_CALBITS_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_SPI_CP_FORCE_CALBITS_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_CP_OFFSET_OFF_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_SPI_CP_OFFSET_OFF_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_CP_ENABLE_MACHINE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_SPI_CP_ENABLE_MACHINE_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_CP_DITHER_MODE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_SPI_CP_DITHER_MODE_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_CP_HALF_VCO_CAL_CLK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_SPI_CP_HALF_VCO_CAL_CLK_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_VCO_BIAS_1 = 0x296 +# default: 0x04, access: R/W +@portable +def AD9154_SPI_VCO_BIAS_REF_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 0 + +@portable +def AD9154_SPI_VCO_BIAS_REF_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x7 + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_VCO_BIAS_TCF_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 3 + +@portable +def AD9154_SPI_VCO_BIAS_TCF_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x3 + + +AD9154_VCO_BIAS_2 = 0x297 +# default: 0x00, access: R/W +@portable +def AD9154_SPI_PRESCALE_BIAS_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 0 + +@portable +def AD9154_SPI_PRESCALE_BIAS_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_LAST_ALC_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_SPI_LAST_ALC_EN_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_PRESCALE_BYPASS_R_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_SPI_PRESCALE_BYPASS_R_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_VCO_COMP_BYPASS_BIASR_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_SPI_VCO_COMP_BYPASS_BIASR_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_VCO_BYPASS_DAC_R_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_SPI_VCO_BYPASS_DAC_R_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + + +AD9154_VCO_PD_OVERRIDES = 0x299 +# default: 0x00, access: R/W +@portable +def AD9154_SPI_VCO_PD_OVERRIDE_VCO_BUF_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_SPI_VCO_PD_OVERRIDE_VCO_BUF_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_VCO_PD_OVERRIDE_CAL_TCF_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_SPI_VCO_PD_OVERRIDE_CAL_TCF_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_TCF_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_TCF_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + + +AD9154_VCO_CAL = 0x29a +# default: 0x02, access: R/W +@portable +def AD9154_SPI_FB_CLOCK_ADV_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 0 + +@portable +def AD9154_SPI_FB_CLOCK_ADV_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3 + +# default: 0x03, access: R/W +@portable +def AD9154_SPI_VCO_CAL_COUNT_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 2 + +@portable +def AD9154_SPI_VCO_CAL_COUNT_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x3 + +# default: 0x07, access: R/W +@portable +def AD9154_SPI_VCO_CAL_ALC_WAIT_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 4 + +@portable +def AD9154_SPI_VCO_CAL_ALC_WAIT_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x7 + +# default: 0x01, access: R/W +@portable +def AD9154_SPI_VCO_CAL_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_SPI_VCO_CAL_EN_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_CP_LEVEL_DETECT = 0x29c +# default: 0x07, access: R/W +@portable +def AD9154_SPI_CP_LEVEL_THRESHOLD_HIGH_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 0 + +@portable +def AD9154_SPI_CP_LEVEL_THRESHOLD_HIGH_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x7 + +# default: 0x02, access: R/W +@portable +def AD9154_SPI_CP_LEVEL_THRESHOLD_LOW_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 3 + +@portable +def AD9154_SPI_CP_LEVEL_THRESHOLD_LOW_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x7 + +# default: 0x00, access: R/W +@portable +def AD9154_SPI_CP_LEVEL_DET_PD_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_SPI_CP_LEVEL_DET_PD_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + + +AD9154_VCO_VARACTOR_CTRL_0 = 0x29f +# default: 0x03, access: R/W +@portable +def AD9154_SPI_VCO_VARACTOR_OFFSET_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 0 + +@portable +def AD9154_SPI_VCO_VARACTOR_OFFSET_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x03, access: R/W +@portable +def AD9154_SPI_VCO_VARACTOR_REF_TCF_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 4 + +@portable +def AD9154_SPI_VCO_VARACTOR_REF_TCF_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x7 + + +AD9154_VCO_VARACTOR_CTRL_1 = 0x2a0 +# default: 0x08, access: R/W +@portable +def AD9154_SPI_VCO_VARACTOR_REF_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 0 + +@portable +def AD9154_SPI_VCO_VARACTOR_REF_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + + +AD9154_TERM_BLK1_CTRLREG0 = 0x2a7 + +AD9154_TERM_BLK2_CTRLREG0 = 0x2ae + +AD9154_GENERAL_JRX_CTRL_0 = 0x300 +# default: 0x00, access: R/W +@portable +def AD9154_LINK_EN_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 0 + +@portable +def AD9154_LINK_EN_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x3 + +# default: 0x00, access: R/W +@portable +def AD9154_LINK_PAGE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +@portable +def AD9154_LINK_PAGE_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_LINK_MODE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_LINK_MODE_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_CHECKSUM_MODE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_CHECKSUM_MODE_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + + +AD9154_GENERAL_JRX_CTRL_1 = 0x301 + +AD9154_DYN_LINK_LATENCY_0 = 0x302 + +AD9154_DYN_LINK_LATENCY_1 = 0x303 + +AD9154_LMFC_DELAY_0 = 0x304 + +AD9154_LMFC_DELAY_1 = 0x305 + +AD9154_LMFC_VAR_0 = 0x306 + +AD9154_LMFC_VAR_1 = 0x307 + +AD9154_XBAR_LN_0_1 = 0x308 +# default: 0x00, access: R/W +@portable +def AD9154_LOGICAL_LANE0_SRC_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 0 + +@portable +def AD9154_LOGICAL_LANE0_SRC_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x7 + +# default: 0x01, access: R/W +@portable +def AD9154_LOGICAL_LANE1_SRC_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 3 + +@portable +def AD9154_LOGICAL_LANE1_SRC_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x7 + + +AD9154_XBAR_LN_2_3 = 0x309 +# default: 0x02, access: R/W +@portable +def AD9154_LOGICAL_LANE2_SRC_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 0 + +@portable +def AD9154_LOGICAL_LANE2_SRC_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x7 + +# default: 0x03, access: R/W +@portable +def AD9154_LOGICAL_LANE3_SRC_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 3 + +@portable +def AD9154_LOGICAL_LANE3_SRC_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x7 + + +AD9154_XBAR_LN_4_5 = 0x30a +# default: 0x04, access: R/W +@portable +def AD9154_LOGICAL_LANE4_SRC_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 0 + +@portable +def AD9154_LOGICAL_LANE4_SRC_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x7 + +# default: 0x05, access: R/W +@portable +def AD9154_LOGICAL_LANE5_SRC_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 3 + +@portable +def AD9154_LOGICAL_LANE5_SRC_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x7 + + +AD9154_XBAR_LN_6_7 = 0x30b +# default: 0x06, access: R/W +@portable +def AD9154_LOGICAL_LANE6_SRC_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 0 + +@portable +def AD9154_LOGICAL_LANE6_SRC_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x7 + +# default: 0x07, access: R/W +@portable +def AD9154_LOGICAL_LANE7_SRC_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 3 + +@portable +def AD9154_LOGICAL_LANE7_SRC_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x7 + + +AD9154_FIFO_STATUS_REG_0 = 0x30c + +AD9154_FIFO_STATUS_REG_1 = 0x30d + +AD9154_SYNCB_GEN_1 = 0x312 +# default: 0x00, access: R/W +@portable +def AD9154_SYNCB_ERR_DUR_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 4 + +@portable +def AD9154_SYNCB_ERR_DUR_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x7 + + +AD9154_SERDES_SPI_REG = 0x314 + +AD9154_PHY_PRBS_TEST_EN = 0x315 + +AD9154_PHY_PRBS_TEST_CTRL = 0x316 +# default: 0x00, access: R/W +@portable +def AD9154_PHY_TEST_RESET_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_PHY_TEST_RESET_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_PHY_TEST_START_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_PHY_TEST_START_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_PHY_PRBS_PAT_SEL_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 2 + +@portable +def AD9154_PHY_PRBS_PAT_SEL_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x3 + +# default: 0x00, access: R/W +@portable +def AD9154_PHY_SRC_ERR_CNT_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 4 + +@portable +def AD9154_PHY_SRC_ERR_CNT_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x7 + + +AD9154_PHY_PRBS_TEST_THRESHOLD_LOBITS = 0x317 + +AD9154_PHY_PRBS_TEST_THRESHOLD_MIDBITS = 0x318 + +AD9154_PHY_PRBS_TEST_THRESHOLD_HIBITS = 0x319 + +AD9154_PHY_PRBS_TEST_ERRCNT_LOBITS = 0x31a + +AD9154_PHY_PRBS_TEST_ERRCNT_MIDBITS = 0x31b + +AD9154_PHY_PRBS_TEST_ERRCNT_HIBITS = 0x31c + +AD9154_PHY_PRBS_TEST_STATUS = 0x31d + +AD9154_SHORT_TPL_TEST_0 = 0x32c +# default: 0x00, access: R/W +@portable +def AD9154_SHORT_TPL_TEST_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +@portable +def AD9154_SHORT_TPL_TEST_EN_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SHORT_TPL_TEST_RESET_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_SHORT_TPL_TEST_RESET_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_SHORT_TPL_DAC_SEL_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 2 + +@portable +def AD9154_SHORT_TPL_DAC_SEL_GET(x: TInt32) -> TInt32: + return (x >> 2) & 0x3 + +# default: 0x00, access: R/W +@portable +def AD9154_SHORT_TPL_SP_SEL_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 4 + +@portable +def AD9154_SHORT_TPL_SP_SEL_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x3 + + +AD9154_SHORT_TPL_TEST_1 = 0x32d + +AD9154_SHORT_TPL_TEST_2 = 0x32e + +AD9154_SHORT_TPL_TEST_3 = 0x32f + +AD9154_DEVICE_CONFIG_REG_2 = 0x333 + +AD9154_JESD_BIT_INVERSE_CTRL = 0x334 + +AD9154_DID_REG = 0x400 + +AD9154_BID_REG = 0x401 +# default: 0x00, access: R +@portable +def AD9154_BID_RD_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x00, access: R +@portable +def AD9154_ADJCNT_RD_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0xf + + +AD9154_LID0_REG = 0x402 +# default: 0x00, access: R +@portable +def AD9154_LID0_RD_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x00, access: R +@portable +def AD9154_PHADJ_RD_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R +@portable +def AD9154_ADJDIR_RD_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + + +AD9154_SCR_L_REG = 0x403 +# default: 0x00, access: R +@portable +def AD9154_L_1_RD_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x00, access: R +@portable +def AD9154_SCR_RD_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_F_REG = 0x404 + +AD9154_K_REG = 0x405 + +AD9154_M_REG = 0x406 + +AD9154_CS_N_REG = 0x407 +# default: 0x00, access: R +@portable +def AD9154_N_1_RD_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x00, access: R +@portable +def AD9154_CS_RD_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x3 + + +AD9154_NP_REG = 0x408 +# default: 0x00, access: R +@portable +def AD9154_NP_1_RD_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x00, access: R +@portable +def AD9154_SUBCLASSV_RD_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x7 + + +AD9154_S_REG = 0x409 +# default: 0x00, access: R +@portable +def AD9154_S_1_RD_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x00, access: R +@portable +def AD9154_JESDV_RD_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x7 + + +AD9154_HD_CF_REG = 0x40a +# default: 0x00, access: R +@portable +def AD9154_CF_RD_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x00, access: R +@portable +def AD9154_HD_RD_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_RES1_REG = 0x40b + +AD9154_RES2_REG = 0x40c + +AD9154_CHECKSUM0_REG = 0x40d + +AD9154_COMPSUM0_REG = 0x40e + +AD9154_LID1_REG = 0x412 + +AD9154_CHECKSUM1_REG = 0x415 + +AD9154_COMPSUM1_REG = 0x416 + +AD9154_LID2_REG = 0x41a + +AD9154_CHECKSUM2_REG = 0x41d + +AD9154_COMPSUM2_REG = 0x41e + +AD9154_LID3_REG = 0x422 + +AD9154_CHECKSUM3_REG = 0x425 + +AD9154_COMPSUM3_REG = 0x426 + +AD9154_LID4_REG = 0x42a + +AD9154_CHECKSUM4_REG = 0x42d + +AD9154_COMPSUM4_REG = 0x42e + +AD9154_LID5_REG = 0x432 + +AD9154_CHECKSUM5_REG = 0x435 + +AD9154_COMPSUM5_REG = 0x436 + +AD9154_LID6_REG = 0x43a + +AD9154_CHECKSUM6_REG = 0x43d + +AD9154_COMPSUM6_REG = 0x43e + +AD9154_LID7_REG = 0x442 + +AD9154_CHECKSUM7_REG = 0x445 + +AD9154_COMPSUM7_REG = 0x446 + +AD9154_ILS_DID = 0x450 + +AD9154_ILS_BID = 0x451 +# default: 0x00, access: R/W +@portable +def AD9154_BID_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 0 + +@portable +def AD9154_BID_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0xf + +# default: 0x00, access: R/W +@portable +def AD9154_ADJCNT_SET(x: TInt32) -> TInt32: + return (x & 0xf) << 4 + +@portable +def AD9154_ADJCNT_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0xf + + +AD9154_ILS_LID0 = 0x452 +# default: 0x00, access: R/W +@portable +def AD9154_LID0_SET(x: TInt32) -> TInt32: + return (x & 0x1f) << 0 + +@portable +def AD9154_LID0_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x00, access: R/W +@portable +def AD9154_PHADJ_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_PHADJ_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_ADJDIR_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_ADJDIR_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + + +AD9154_ILS_SCR_L = 0x453 +# default: 0x03, access: R/W +@portable +def AD9154_L_1_SET(x: TInt32) -> TInt32: + return (x & 0x1f) << 0 + +@portable +def AD9154_L_1_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x01, access: R/W +@portable +def AD9154_SCR_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_SCR_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_ILS_F = 0x454 + +AD9154_ILS_K = 0x455 + +AD9154_ILS_M = 0x456 + +AD9154_ILS_CS_N = 0x457 +# default: 0x0f, access: R/W +@portable +def AD9154_N_1_SET(x: TInt32) -> TInt32: + return (x & 0x1f) << 0 + +@portable +def AD9154_N_1_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x00, access: R/W +@portable +def AD9154_CS_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 6 + +@portable +def AD9154_CS_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x3 + + +AD9154_ILS_NP = 0x458 +# default: 0x0f, access: R/W +@portable +def AD9154_NP_1_SET(x: TInt32) -> TInt32: + return (x & 0x1f) << 0 + +@portable +def AD9154_NP_1_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x01, access: R/W +@portable +def AD9154_SUBCLASSV_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 5 + +@portable +def AD9154_SUBCLASSV_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x7 + + +AD9154_ILS_S = 0x459 +# default: 0x00, access: R/W +@portable +def AD9154_S_1_SET(x: TInt32) -> TInt32: + return (x & 0x1f) << 0 + +@portable +def AD9154_S_1_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x01, access: R/W +@portable +def AD9154_JESDV_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 5 + +@portable +def AD9154_JESDV_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x7 + + +AD9154_ILS_HD_CF = 0x45a +# default: 0x00, access: R/W +@portable +def AD9154_CF_SET(x: TInt32) -> TInt32: + return (x & 0x1f) << 0 + +@portable +def AD9154_CF_GET(x: TInt32) -> TInt32: + return (x >> 0) & 0x1f + +# default: 0x01, access: R/W +@portable +def AD9154_HD_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_HD_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_ILS_RES1 = 0x45b + +AD9154_ILS_RES2 = 0x45c + +AD9154_ILS_CHECKSUM = 0x45d + +AD9154_ERRCNTRMON = 0x46b +# default: 0x00, access: W +@portable +def AD9154_CNTRSEL_SET(x: TInt32) -> TInt32: + return (x & 0x3) << 0 + +# default: 0x00, access: W +@portable +def AD9154_LANESEL_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 4 + + +AD9154_LANEDESKEW = 0x46c + +AD9154_BADDISPARITY = 0x46d +# default: 0x00, access: W +@portable +def AD9154_LANE_ADDR_DIS_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 0 + +# default: 0x00, access: W +@portable +def AD9154_RST_ERR_CNTR_DIS_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +# default: 0x00, access: W +@portable +def AD9154_DISABLE_ERR_CNTR_DIS_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +# default: 0x00, access: W +@portable +def AD9154_RST_IRQ_DIS_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + + +AD9154_NIT_W = 0x46e +# default: 0x00, access: W +@portable +def AD9154_LANE_ADDR_NIT_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 0 + +# default: 0x00, access: W +@portable +def AD9154_RST_ERR_CNTR_NIT_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +# default: 0x00, access: W +@portable +def AD9154_DISABLE_ERR_CNTR_NIT_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +# default: 0x00, access: W +@portable +def AD9154_RST_IRQ_NIT_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + + +AD9154_UNEXPECTEDCONTROL_W = 0x46f +# default: 0x00, access: W +@portable +def AD9154_LANE_ADDR_UCC_SET(x: TInt32) -> TInt32: + return (x & 0x7) << 0 + +# default: 0x00, access: W +@portable +def AD9154_RST_ERR_CNTR_UCC_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +# default: 0x00, access: W +@portable +def AD9154_DISABLE_ERR_CNTR_UCC_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +# default: 0x00, access: W +@portable +def AD9154_RST_IRQ_UCC_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + + +AD9154_CODEGRPSYNCFLG = 0x470 + +AD9154_FRAMESYNCFLG = 0x471 + +AD9154_GOODCHKSUMFLG = 0x472 + +AD9154_INITLANESYNCFLG = 0x473 + +AD9154_CTRLREG1 = 0x476 + +AD9154_CTRLREG2 = 0x477 +# default: 0x00, access: R/W +@portable +def AD9154_THRESHOLD_MASK_EN_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_THRESHOLD_MASK_EN_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_ILAS_MODE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_ILAS_MODE_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_KVAL = 0x478 + +AD9154_IRQVECTOR_MASK = 0x47a +# default: 0x00, access: W +@portable +def AD9154_CODEGRPSYNC_MASK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 0 + +# default: 0x00, access: W +@portable +def AD9154_BADCHECKSUM_MASK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 2 + +# default: 0x00, access: W +@portable +def AD9154_INITIALLANESYNC_MASK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +# default: 0x00, access: W +@portable +def AD9154_UCC_MASK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +# default: 0x00, access: W +@portable +def AD9154_NIT_MASK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +# default: 0x00, access: W +@portable +def AD9154_BADDIS_MASK_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + + +AD9154_SYNCASSERTIONMASK = 0x47b +# default: 0x01, access: R/W +@portable +def AD9154_CMM_ENABLE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 3 + +@portable +def AD9154_CMM_ENABLE_GET(x: TInt32) -> TInt32: + return (x >> 3) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_CMM_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + +@portable +def AD9154_CMM_GET(x: TInt32) -> TInt32: + return (x >> 4) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_UCC_S_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + +@portable +def AD9154_UCC_S_GET(x: TInt32) -> TInt32: + return (x >> 5) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_NIT_S_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + +@portable +def AD9154_NIT_S_GET(x: TInt32) -> TInt32: + return (x >> 6) & 0x1 + +# default: 0x00, access: R/W +@portable +def AD9154_BADDIS_S_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + +@portable +def AD9154_BADDIS_S_GET(x: TInt32) -> TInt32: + return (x >> 7) & 0x1 + + +AD9154_ERRORTHRES = 0x47c + +AD9154_LANEENABLE = 0x47d + +AD9154_RAMP_ENA = 0x47e + +AD9154_DIG_TEST0 = 0x520 +# default: 0x00, access: R/W +@portable +def AD9154_DC_TEST_MODE_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 1 + +@portable +def AD9154_DC_TEST_MODE_GET(x: TInt32) -> TInt32: + return (x >> 1) & 0x1 + + +AD9154_DC_TEST_VALUEI0 = 0x521 + +AD9154_DC_TEST_VALUEI1 = 0x522 + +AD9154_DC_TEST_VALUEQ0 = 0x523 + +AD9154_DC_TEST_VALUEQ1 = 0x524 diff --git a/artiq/coredevice/ad9516_reg.py b/artiq/coredevice/ad9516_reg.py new file mode 100644 index 000000000..7b228baa1 --- /dev/null +++ b/artiq/coredevice/ad9516_reg.py @@ -0,0 +1,291 @@ +# = auto-generated, do not edit +from artiq.language.core import kernel + + +AD9516_SERIAL_PORT_CONFIGURATION = 0x000 +AD9516_SDO_ACTIVE = 1 << 0 # 1, 0x00 R/W +AD9516_LSB_FIRST = 1 << 1 # 1, 0x00 R/W +AD9516_SOFT_RESET = 1 << 2 # 1, 0x00 R/W +AD9516_LONG_INSTRUCTION = 1 << 3 # 1, 0x01 R/W +AD9516_LONG_INSTRUCTION_MIRRORED = 1 << 4 # 1, 0x01 R/W +AD9516_SOFT_RESET_MIRRORED = 1 << 5 # 1, 0x00 R/W +AD9516_LSB_FIRST_MIRRORED = 1 << 6 # 1, 0x00 R/W +AD9516_SDO_ACTIVE_MIRRORED = 1 << 7 # 1, 0x00 R/W + +AD9516_PART_ID = 0x003 + +AD9516_READBACK_CONTROL = 0x004 +AD9516_READ_BACK_ACTIVE_REGISTERS = 1 << 0 # 1, 0x00 R/W + +AD9516_PFD_AND_CHARGE_PUMP = 0x010 +AD9516_PLL_POWER_DOWN = 1 << 0 # 2, 0x01 R/W +AD9516_CHARGE_PUMP_MODE = 1 << 2 # 2, 0x03 R/W +AD9516_CHARGE_PUMP_CURRENT = 1 << 4 # 3, 0x07 R/W +AD9516_PFD_POLARITY = 1 << 7 # 1, 0x00 R/W + +AD9516_R_COUNTER_LSB = 0x011 +AD9516_R_COUNTER_MSB = 0x012 + +AD9516_A_COUNTER = 0x013 + +AD9516_B_COUNTER_LSB = 0x014 +AD9516_B_COUNTER_MSB = 0x015 + +AD9516_PLL_CONTROL_1 = 0x016 +AD9516_PRESCALER_P = 1 << 0 # 3, 0x06 R/W +AD9516_B_COUNTER_BYPASS = 1 << 3 # 1, 0x00 R/W +AD9516_RESET_ALL_COUNTERS = 1 << 4 # 1, 0x00 R/W +AD9516_RESET_A_AND_B_COUNTERS = 1 << 5 # 1, 0x00 R/W +AD9516_RESET_R_COUNTER = 1 << 6 # 1, 0x00 R/W +AD9516_SET_CP_PIN_TO_VCP_2 = 1 << 7 # 1, 0x00 R/W + +AD9516_PLL_CONTROL_2 = 0x017 +AD9516_ANTIBACKLASH_PULSE_WIDTH = 1 << 0 # 2, 0x00 R/W +AD9516_STATUS_PIN_CONTROL = 1 << 2 # 6, 0x00 R/W + +AD9516_PLL_CONTROL_3 = 0x018 +AD9516_VCO_CAL_NOW = 1 << 0 # 1, 0x00 R/W +AD9516_VCO_CALIBRATION_DIVIDER = 1 << 1 # 2, 0x03 R/W +AD9516_DISABLE_DIGITAL_LOCK_DETECT = 1 << 3 # 1, 0x00 R/W +AD9516_DIGITAL_LOCK_DETECT_WINDOW = 1 << 4 # 1, 0x00 R/W +AD9516_LOCK_DETECT_COUNTER = 1 << 5 # 2, 0x00 R/W + +AD9516_PLL_CONTROL_4 = 0x019 +AD9516_N_PATH_DELAY = 1 << 0 # 3, 0x00 R/W +AD9516_R_PATH_DELAY = 1 << 3 # 3, 0x00 R/W +AD9516_R_A_B_COUNTERS_SYNC_PIN_RESET = 1 << 6 # 2, 0x00 R/W + +AD9516_PLL_CONTROL_5 = 0x01a +AD9516_LD_PIN_CONTROL = 1 << 0 # 6, 0x00 R/W +AD9516_REFERENCE_FREQUENCY_MONITOR_THRESHOLD = 1 << 6 # 1, 0x00 R/W + +AD9516_PLL_CONTROL_6 = 0x01b +AD9516_REFMON_PIN_CONTROL = 1 << 0 # 5, 0x00 R/W +AD9516_REF1_REFIN_FREQUENCY_MONITOR = 1 << 5 # 1, 0x00 R/W +AD9516_REF2_REFIN_FREQUENCY_MONITOR = 1 << 6 # 1, 0x00 R/W +AD9516_VCO_FREQUENCY_MONITOR = 1 << 7 # 1, 0x00 R/W + +AD9516_PLL_CONTROL_7 = 0x01c +AD9516_DIFFERENTIAL_REFERENCE = 1 << 0 # 1, 0x00 R/W +AD9516_REF1_POWER_ON = 1 << 1 # 1, 0x00 R/W +AD9516_REF2_POWER_ON = 1 << 2 # 1, 0x00 R/W +AD9516_USE_REF_SEL_PIN = 1 << 5 # 1, 0x00 R/W +AD9516_SELECT_REF2 = 1 << 6 # 1, 0x00 R/W +AD9516_DISABLE_SWITCHOVER_DEGLITCH = 1 << 7 # 1, 0x00 R/W + +AD9516_PLL_CONTROL_8 = 0x01d +AD9516_HOLDOVER_ENABLE = 1 << 0 # 1, 0x00 R/W +AD9516_EXTERNAL_HOLDOVER_CONTROL = 1 << 1 # 1, 0x00 R/W +AD9516_HOLDOVER_ENABLEreg001D = 1 << 2 # 1, 0x00 R/W +AD9516_LD_PIN_COMPARATOR_ENABLE = 1 << 3 # 1, 0x00 R/W +AD9516_PLL_STATUS_REGISTER_DISABLE = 1 << 4 # 1, 0x00 R/W + +AD9516_PLL_READBACK = 0x01f +AD9516_DIGITAL_LOCK_DETECT = 1 << 0 # 1, 0x00 R +AD9516_REF1_FREQUENCY_THRESHOLD = 1 << 1 # 1, 0x00 R +AD9516_REF2_FREQUENCY_THRESHOLD = 1 << 2 # 1, 0x00 R +AD9516_VCO_FREQUENCY_THRESHOLD = 1 << 3 # 1, 0x00 R +AD9516_REF2_SELECTED = 1 << 4 # 1, 0x00 R +AD9516_HOLDOVER_ACTIVE = 1 << 5 # 1, 0x00 R +AD9516_VCO_CAL_FINISHED = 1 << 6 # 1, 0x00 R + +AD9516_OUT6_DELAY_BYPASS = 0x0a0 + +AD9516_OUT6_DELAY_FULL_SCALE = 0x0a1 +AD9516_OUT6_RAMP_CURRENT = 1 << 0 # 3, 0x00 R/W +AD9516_OUT6_RAMP_CAPACITORS = 1 << 3 # 3, 0x00 R/W + +AD9516_OUT6_DELAY_FRACTION = 0x0a2 + +AD9516_OUT7_DELAY_BYPASS = 0x0a3 + +AD9516_OUT7_DELAY_FULL_SCALE = 0x0a4 +AD9516_OUT7_RAMP_CURRENT = 1 << 0 # 3, 0x00 R/W +AD9516_OUT7_RAMP_CAPACITORS = 1 << 3 # 3, 0x00 R/W + +AD9516_OUT7_DELAY_FRACTION = 0x0a5 + +AD9516_OUT8_DELAY_BYPASS = 0x0a6 + +AD9516_OUT8_DELAY_FULL_SCALE = 0x0a7 +AD9516_OUT8_RAMP_CURRENT = 1 << 0 # 3, 0x00 R/W +AD9516_OUT8_RAMP_CAPACITORS = 1 << 3 # 3, 0x00 R/W + +AD9516_OUT8_DELAY_FRACTION = 0x0a8 + +AD9516_OUT9_DELAY_BYPASS = 0x0a9 + +AD9516_OUT9_DELAY_FULL_SCALE = 0x0aa +AD9516_OUT9_RAMP_CURRENT = 1 << 0 # 3, 0x00 R/W +AD9516_OUT9_RAMP_CAPACITORS = 1 << 3 # 3, 0x00 R/W + +AD9516_OUT9_DELAY_FRACTION = 0x0ab + +AD9516_OUT0 = 0x0f0 +AD9516_OUT0_POWER_DOWN = 1 << 0 # 2, 0x00 R/W +AD9516_OUT0_LVPECL_DIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W +AD9516_OUT0_INVERT = 1 << 4 # 1, 0x00 R/W + +AD9516_OUT1 = 0x0f1 +AD9516_OUT1_POWER_DOWN = 1 << 0 # 2, 0x02 R/W +AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W +AD9516_OUT1_INVERT = 1 << 4 # 1, 0x00 R/W + +AD9516_OUT2 = 0x0f2 +AD9516_OUT2_POWER_DOWN = 1 << 0 # 2, 0x00 R/W +AD9516_OUT2_LVPECL_DIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W +AD9516_OUT2_INVERT = 1 << 4 # 1, 0x00 R/W + +AD9516_OUT3 = 0x0f3 +AD9516_OUT3_POWER_DOWN = 1 << 0 # 2, 0x02 R/W +AD9516_OUT3_LVPECL_DIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W +AD9516_OUT3_INVERT = 1 << 4 # 1, 0x00 R/W + +AD9516_OUT4 = 0x0f4 +AD9516_OUT4_POWER_DOWN = 1 << 0 # 2, 0x02 R/W +AD9516_OUT4_LVPECL_DIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W +AD9516_OUT4_INVERT = 1 << 4 # 1, 0x00 R/W + +AD9516_OUT5 = 0x0f5 +AD9516_OUT5_POWER_DOWN = 1 << 0 # 2, 0x02 R/W +AD9516_OUT5_LVPECL_DIFFERENTIAL_VOLTAGE = 1 << 2 # 2, 0x02 R/W +AD9516_OUT5_INVERT = 1 << 4 # 1, 0x00 R/W + +AD9516_OUT6 = 0x140 +AD9516_OUT6_POWER_DOWN = 1 << 0 # 1, 0x00 R/W +AD9516_OUT6_LVDS_OUTPUT_CURRENT = 1 << 1 # 2, 0x01 R/W +AD9516_OUT6_SELECT_LVDS_CMOS = 1 << 3 # 1, 0x00 R/W +AD9516_OUT6_CMOS_B = 1 << 4 # 1, 0x00 R/W +AD9516_OUT6_LVDS_CMOS_OUTPUT_POLARITY = 1 << 5 # 1, 0x00 R/W +AD9516_OUT6_CMOS_OUTPUT_POLARITY = 1 << 6 # 2, 0x01 R/W + +AD9516_OUT7 = 0x141 +AD9516_OUT7_POWER_DOWN = 1 << 0 # 1, 0x01 R/W +AD9516_OUT7_LVDS_OUTPUT_CURRENT = 1 << 1 # 2, 0x01 R/W +AD9516_OUT7_SELECT_LVDS_CMOS = 1 << 3 # 1, 0x00 R/W +AD9516_OUT7_CMOS_B = 1 << 4 # 1, 0x00 R/W +AD9516_OUT7_LVDS_CMOS_OUTPUT_POLARITY = 1 << 5 # 1, 0x00 R/W +AD9516_OUT7_CMOS_OUTPUT_POLARITY = 1 << 6 # 2, 0x01 R/W + +AD9516_OUT8 = 0x142 +AD9516_OUT8_POWER_DOWN = 1 << 0 # 1, 0x00 R/W +AD9516_OUT8_LVDS_OUTPUT_CURRENT = 1 << 1 # 2, 0x01 R/W +AD9516_OUT8_SELECT_LVDS_CMOS = 1 << 3 # 1, 0x00 R/W +AD9516_OUT8_CMOS_B = 1 << 4 # 1, 0x00 R/W +AD9516_OUT8_LVDS_CMOS_OUTPUT_POLARITY = 1 << 5 # 1, 0x00 R/W +AD9516_OUT8_CMOS_OUTPUT_POLARITY = 1 << 6 # 2, 0x01 R/W + +AD9516_OUT9 = 0x143 +AD9516_OUT9_POWER_DOWN = 1 << 0 # 1, 0x01 R/W +AD9516_OUT9_LVDS_OUTPUT_CURRENT = 1 << 1 # 2, 0x01 R/W +AD9516_OUT9_SELECT_LVDS_CMOS = 1 << 3 # 1, 0x00 R/W +AD9516_OUT9_CMOS_B = 1 << 4 # 1, 0x00 R/W +AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY = 1 << 5 # 1, 0x00 R/W +AD9516_OUT9_CMOS_OUTPUT_POLARITY = 1 << 6 # 2, 0x01 R/W + +AD9516_DIVIDER_0_0 = 0x190 +AD9516_DIVIDER_0_HIGH_CYCLES = 1 << 0 # 4, 0x00 R/W +AD9516_DIVIDER_0_LOW_CYCLES = 1 << 4 # 4, 0x00 R/W + +AD9516_DIVIDER_0_1 = 0x191 +AD9516_DIVIDER_0_PHASE_OFFSET = 1 << 0 # 4, 0x00 R/W +AD9516_DIVIDER_0_START_HIGH = 1 << 4 # 1, 0x00 R/W +AD9516_DIVIDER_0_FORCE_HIGH = 1 << 5 # 1, 0x00 R/W +AD9516_DIVIDER_0_NOSYNC = 1 << 6 # 1, 0x00 R/W +AD9516_DIVIDER_0_BYPASS = 1 << 7 # 1, 0x01 R/W + +AD9516_DIVIDER_0_2 = 0x192 +AD9516_DIVIDER_0_DCCOFF = 1 << 0 # 1, 0x00 R/W +AD9516_DIVIDER_0_DIRECT_TO_OUTPUT = 1 << 1 # 1, 0x00 R/W + +AD9516_DIVIDER_1_0 = 0x193 +AD9516_DIVIDER_1_HIGH_CYCLES = 1 << 0 # 4, 0x00 R/W +AD9516_DIVIDER_1_LOW_CYCLES = 1 << 4 # 4, 0x00 R/W + +AD9516_DIVIDER_1_1 = 0x194 +AD9516_DIVIDER_1_PHASE_OFFSET = 1 << 0 # 4, 0x00 R/W +AD9516_DIVIDER_1_START_HIGH = 1 << 4 # 1, 0x00 R/W +AD9516_DIVIDER_1_FORCE_HIGH = 1 << 5 # 1, 0x00 R/W +AD9516_DIVIDER_1_NOSYNC = 1 << 6 # 1, 0x00 R/W +AD9516_DIVIDER_1_BYPASS = 1 << 7 # 1, 0x00 R/W + +AD9516_DIVIDER_1_2 = 0x195 +AD9516_DIVIDER_1_DCCOFF = 1 << 0 # 1, 0x00 R/W +AD9516_DIVIDER_1_DIRECT_TO_OUTPUT = 1 << 1 # 1, 0x00 R/W + +AD9516_DIVIDER_2_0 = 0x196 +AD9516_DIVIDER_2_HIGH_CYCLES = 1 << 0 # 4, 0x00 R/W +AD9516_DIVIDER_2_LOW_CYCLES = 1 << 4 # 4, 0x00 R/W + +AD9516_DIVIDER_2_1 = 0x197 +AD9516_DIVIDER_2_PHASE_OFFSET = 1 << 0 # 4, 0x00 R/W +AD9516_DIVIDER_2_START_HIGH = 1 << 4 # 1, 0x00 R/W +AD9516_DIVIDER_2_FORCE_HIGH = 1 << 5 # 1, 0x00 R/W +AD9516_DIVIDER_2_NOSYNC = 1 << 6 # 1, 0x00 R/W +AD9516_DIVIDER_2_BYPASS = 1 << 7 # 1, 0x00 R/W + +AD9516_DIVIDER_2_2 = 0x198 +AD9516_DIVIDER_2_DCCOFF = 1 << 0 # 1, 0x00 R/W +AD9516_DIVIDER_2_DIRECT_TO_OUTPUT = 1 << 1 # 1, 0x00 R/W + +AD9516_DIVIDER_3_0 = 0x199 +AD9516_DIVIDER_3_HIGH_CYCLES_1 = 1 << 0 # 4, 0x02 R/W +AD9516_DIVIDER_3_LOW_CYCLES_1 = 1 << 4 # 4, 0x02 R/W + +AD9516_DIVIDER_3_1 = 0x19a +AD9516_DIVIDER_3_PHASE_OFFSET_1 = 1 << 0 # 4, 0x00 R/W +AD9516_DIVIDER_3_PHASE_OFFSET_2 = 1 << 4 # 4, 0x00 R/W + +AD9516_DIVIDER_3_2 = 0x19b +AD9516_DIVIDER_3_HIGH_CYCLES_2 = 1 << 0 # 4, 0x01 R/W +AD9516_DIVIDER_3_LOW_CYCLES_2 = 1 << 4 # 4, 0x01 R/W + +AD9516_DIVIDER_3_3 = 0x19c +AD9516_DIVIDER_3_START_HIGH_1 = 1 << 0 # 1, 0x00 R/W +AD9516_DIVIDER_3_START_HIGH_2 = 1 << 1 # 1, 0x00 R/W +AD9516_DIVIDER_3_FORCE_HIGH = 1 << 2 # 1, 0x00 R/W +AD9516_DIVIDER_3_NOSYNC = 1 << 3 # 1, 0x00 R/W +AD9516_DIVIDER_3_BYPASS_1 = 1 << 4 # 1, 0x00 R/W +AD9516_DIVIDER_3_BYPASS_2 = 1 << 5 # 1, 0x00 R/W + +AD9516_DIVIDER_3_4 = 0x19d +AD9516_DIVIDER_3_DCCOFF = 1 << 0 # 1, 0x00 R/W + +AD9516_DIVIDER_4_0 = 0x19e +AD9516_DIVIDER_4_HIGH_CYCLES_1 = 1 << 0 # 4, 0x02 R/W +AD9516_DIVIDER_4_LOW_CYCLES_1 = 1 << 4 # 4, 0x02 R/W + +AD9516_DIVIDER_4_1 = 0x19f +AD9516_DIVIDER_4_PHASE_OFFSET_1 = 1 << 0 # 4, 0x00 R/W +AD9516_DIVIDER_4_PHASE_OFFSET_2 = 1 << 4 # 4, 0x00 R/W + +AD9516_DIVIDER_4_2 = 0x1a0 +AD9516_DIVIDER_4_HIGH_CYCLES_2 = 1 << 0 # 4, 0x01 R/W +AD9516_DIVIDER_4_LOW_CYCLES_2 = 1 << 4 # 4, 0x01 R/W + +AD9516_DIVIDER_4_3 = 0x1a1 +AD9516_DIVIDER_4_START_HIGH_1 = 1 << 0 # 1, 0x00 R/W +AD9516_DIVIDER_4_START_HIGH_2 = 1 << 1 # 1, 0x00 R/W +AD9516_DIVIDER_4_FORCE_HIGH = 1 << 2 # 1, 0x00 R/W +AD9516_DIVIDER_4_NOSYNC = 1 << 3 # 1, 0x00 R/W +AD9516_DIVIDER_4_BYPASS_1 = 1 << 4 # 1, 0x00 R/W +AD9516_DIVIDER_4_BYPASS_2 = 1 << 5 # 1, 0x00 R/W + +AD9516_DIVIDER_4_4 = 0x1a2 +AD9516_DIVIDER_4_DCCOFF = 1 << 0 # 1, 0x00 R/W + +AD9516_VCO_DIVIDER = 0x1e0 + +AD9516_INPUT_CLKS = 0x1e1 +AD9516_BYPASS_VCO_DIVIDER = 1 << 0 # 1, 0x00 R/W +AD9516_SELECT_VCO_OR_CLK = 1 << 1 # 1, 0x00 R/W +AD9516_POWER_DOWN_VCO_AND_CLK = 1 << 2 # 1, 0x00 R/W +AD9516_POWER_DOWN_VCO_CLOCK_INTERFACE = 1 << 3 # 1, 0x00 R/W +AD9516_POWER_DOWN_CLOCK_INPUT_SECTION = 1 << 4 # 1, 0x00 R/W + +AD9516_POWER_DOWN_AND_SYNC = 0x230 +AD9516_SOFT_SYNC = 1 << 0 # 1, 0x00 R/W +AD9516_POWER_DOWN_DISTRIBUTION_REFERENCE = 1 << 1 # 1, 0x00 R/W +AD9516_POWER_DOWN_SYNC = 1 << 2 # 1, 0x00 R/W + +AD9516_UPDATE_ALL_REGISTERS = 0x232 diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py new file mode 100644 index 000000000..2732b1e03 --- /dev/null +++ b/artiq/coredevice/sawg.py @@ -0,0 +1,73 @@ +from artiq.language.core import kernel, now_mu +from artiq.coredevice.rtio import rtio_output +from artiq.language.types import TInt32, TFloat + + +class SAWG: + """Smart arbitrary waveform generator channel. + + :param channel_base: RTIO channel number of the first channel (amplitude). + Frequency and Phase are then assumed to be successive channels. + """ + kernel_invariants = {"amplitude_scale", "frequency_scale", "phase_scale", + "channel_base"} + + def __init__(self, dmgr, channel_base, parallelism=4, core_device="core"): + self.core = dmgr.get(core_device) + self.channel_base = channel_base + cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain + a_width = 16 + f_width = 32 + p_width = 16 + self.amplitude_scale = (1 << a_width) / 2 / cordic_gain + self.phase_scale = 1 << p_width + self.frequency_scale = ((1 << f_width) * self.core.coarse_ref_period / + parallelism) + + @kernel + def set_amplitude_mu(self, amplitude: TInt32): + """Set DDS amplitude (machine units). + + :param amplitude: DDS amplitude in machine units. + """ + rtio_output(now_mu(), self.channel_base, 0, amplitude) + + @kernel + def set_amplitude(self, amplitude: TFloat): + """Set DDS amplitude. + + :param amplitude: DDS amplitude relative to full-scale. + """ + self.set_amplitude_mu(int(amplitude*self.amplitude_scale)) + + @kernel + def set_frequency_mu(self, frequency: TInt32): + """Set DDS frequency (machine units). + + :param frequency: DDS frequency in machine units. + """ + rtio_output(now_mu(), self.channel_base + 1, 0, frequency) + + @kernel + def set_frequency(self, frequency: TFloat): + """Set DDS frequency. + + :param frequency: DDS frequency in Hz. + """ + self.set_frequency_mu(int(frequency*self.frequency_scale)) + + @kernel + def set_phase_mu(self, phase: TInt32): + """Set DDS phase (machine units). + + :param phase: DDS phase in machine units. + """ + rtio_output(now_mu(), self.channel_base + 2, 0, phase) + + @kernel + def set_phase(self, phase: TFloat): + """Set DDS phase. + + :param phase: DDS phase relative in turns. + """ + self.set_phase_mu(int(phase*self.phase_scale)) diff --git a/artiq/examples/phaser/device_db.pyon b/artiq/examples/phaser/device_db.pyon new file mode 100644 index 000000000..c9bfe06f5 --- /dev/null +++ b/artiq/examples/phaser/device_db.pyon @@ -0,0 +1,77 @@ +# The RTIO channel numbers here are for Phaser on KC705. + +{ + "comm": { + "type": "local", + "module": "artiq.coredevice.comm_tcp", + "class": "Comm", + "arguments": {"host": "kc705aux.lab.m-labs.hk"} + }, + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": { + "ref_period": 1e-9, + "external_clock": True + } + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "ad9154": { + "type": "local", + "module": "artiq.coredevice.ad9154", + "class": "AD9154" + }, + "ttl_sma": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 0} + }, + "led": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 1} + }, + "sysref": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 2} + }, + "sync": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 3} + }, + "sawg0": { + "type": "local", + "module": "artiq.coredevice.sawg", + "class": "SAWG", + "arguments": {"channel_base": 4, "parallelism": 4} + }, + "sawg1": { + "type": "local", + "module": "artiq.coredevice.sawg", + "class": "SAWG", + "arguments": {"channel_base": 7, "parallelism": 4} + }, + "sawg2": { + "type": "local", + "module": "artiq.coredevice.sawg", + "class": "SAWG", + "arguments": {"channel_base": 10, "parallelism": 4} + }, + "sawg3": { + "type": "local", + "module": "artiq.coredevice.sawg", + "class": "SAWG", + "arguments": {"channel_base": 13, "parallelism": 4} + } +} diff --git a/artiq/examples/phaser/idle_kernel.py b/artiq/examples/phaser/idle_kernel.py new file mode 100644 index 000000000..704787fb1 --- /dev/null +++ b/artiq/examples/phaser/idle_kernel.py @@ -0,0 +1,21 @@ +from artiq.experiment import * + + +class IdleKernel(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("led") + + @kernel + def run(self): + start_time = now_mu() + seconds_to_mu(500*ms) + while self.core.get_rtio_counter_mu() < start_time: + pass + self.core.reset() + while True: + self.led.pulse(250*ms) + delay(125*ms) + self.led.pulse(125*ms) + delay(125*ms) + self.led.pulse(125*ms) + delay(250*ms) diff --git a/artiq/examples/phaser/repository/sawg.py b/artiq/examples/phaser/repository/sawg.py new file mode 100644 index 000000000..6c13d5b9a --- /dev/null +++ b/artiq/examples/phaser/repository/sawg.py @@ -0,0 +1,34 @@ +from artiq.experiment import * + + +class SAWGTest(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("led") + + self.setattr_device("sawg0") + self.setattr_device("sawg1") + self.setattr_device("sawg2") + self.setattr_device("sawg3") + + @kernel + def run(self): + self.core.reset() + + delay(100*us) + self.sawg0.set_amplitude(.1) + self.sawg1.set_amplitude(-1.) + self.sawg2.set_amplitude(.5) + self.sawg3.set_amplitude(.5) + self.sawg0.set_frequency(1*MHz) + self.sawg1.set_frequency(100*MHz) + self.sawg2.set_frequency(200*MHz) + self.sawg3.set_frequency(200*MHz) + self.sawg0.set_phase(0.) + self.sawg1.set_phase(0.) + self.sawg2.set_phase(0.) + self.sawg3.set_phase(.5) + + for i in range(10): + self.led.pulse(100*ms) + delay(100*ms) diff --git a/artiq/examples/phaser/repository/test_ad9154_prbs.py b/artiq/examples/phaser/repository/test_ad9154_prbs.py new file mode 100644 index 000000000..887b45d29 --- /dev/null +++ b/artiq/examples/phaser/repository/test_ad9154_prbs.py @@ -0,0 +1,46 @@ +import time + +from artiq.coredevice.ad9154_reg import * +from artiq.experiment import * + + +class Test(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("ad9154") + + def run(self): + self.prbs(2, 100) # prbs31 + + def p(self, f, *a): + print(f % a) + + def prbs(self, p, t): + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, + AD9154_PHY_PRBS_PAT_SEL_SET(p)) + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_EN, 0xff) + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, + AD9154_PHY_PRBS_PAT_SEL_SET(p) | AD9154_PHY_TEST_RESET_SET(1)) + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, + AD9154_PHY_PRBS_PAT_SEL_SET(p)) + + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_THRESHOLD_LOBITS, t) + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_THRESHOLD_MIDBITS, t >> 8) + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_THRESHOLD_MIDBITS, t >> 16) + + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, AD9154_PHY_PRBS_PAT_SEL_SET(p)) + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, + AD9154_PHY_PRBS_PAT_SEL_SET(p) | AD9154_PHY_TEST_START_SET(1)) + + time.sleep(.5) + + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, AD9154_PHY_PRBS_PAT_SEL_SET(p)) + + self.p("prbs status: 0x%02x", self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_STATUS)) + + for i in range(8): + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, AD9154_PHY_SRC_ERR_CNT_SET(i)) + self.p("prbs errors[%d]: 0x%08x", i, + self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_ERRCNT_LOBITS) | + (self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_ERRCNT_MIDBITS) << 8) | + (self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_ERRCNT_HIBITS) << 16)) diff --git a/artiq/examples/phaser/repository/test_ad9154_status.py b/artiq/examples/phaser/repository/test_ad9154_status.py new file mode 100644 index 000000000..58c16da93 --- /dev/null +++ b/artiq/examples/phaser/repository/test_ad9154_status.py @@ -0,0 +1,126 @@ +from artiq.coredevice.ad9154_reg import * +from artiq.experiment import * + + +class Test(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("ad9154") + + def run(self): + self.print_status() + self.print_temp() + + def p(self, f, *a): + print(f % a) + + def print_temp(self): + self.ad9154.dac_write(AD9154_DIE_TEMP_CTRL0, AD9154_AUXADC_RESERVED_SET(0x10) | + AD9154_AUXADC_ENABLE_SET(1)) + self.ad9154.dac_write(AD9154_DIE_TEMP_UPDATE, 1) + self.p("temp_code %d", self.ad9154.dac_read(AD9154_DIE_TEMP0) | + (self.ad9154.dac_read(AD9154_DIE_TEMP1) << 8)) + self.ad9154.dac_write(AD9154_DIE_TEMP_CTRL0, AD9154_AUXADC_RESERVED_SET(0x10) | + AD9154_AUXADC_ENABLE_SET(0)) + + def print_status(self): + x = self.ad9154.dac_read(AD9154_IRQ_STATUS0) + self.p("LANEFIFOERR: %d, SERPLLLOCK: %d, SERPLLLOST: %d, " + "DACPLLLOCK: %d, DACPLLLOST: %d", + AD9154_LANEFIFOERR_GET(x), AD9154_SERPLLLOCK_GET(x), + AD9154_SERPLLLOST_GET(x), AD9154_DACPLLLOCK_GET(x), + AD9154_DACPLLLOST_GET(x)) + x = self.ad9154.dac_read(AD9154_IRQ_STATUS1) + self.p("PRBS0: %d, PRBS1: %d, PRBS2: %d, PRBS3: %d", + AD9154_PRBS0_GET(x), AD9154_PRBS1_GET(x), + AD9154_PRBS2_GET(x), AD9154_PRBS3_GET(x)) + x = self.ad9154.dac_read(AD9154_IRQ_STATUS2) + self.p("SYNC_TRIP0: %d, SYNC_WLIM0: %d, SYNC_ROTATE0: %d, " + "SYNC_LOCK0: %d, NCO_ALIGN0: %d, BLNKDONE0: %d, " + "PDPERR0: %d", + AD9154_SYNC_TRIP0_GET(x), AD9154_SYNC_WLIM0_GET(x), + AD9154_SYNC_ROTATE0_GET(x), AD9154_SYNC_LOCK0_GET(x), + AD9154_NCO_ALIGN0_GET(x), AD9154_BLNKDONE0_GET(x), + AD9154_PDPERR0_GET(x)) + x = self.ad9154.dac_read(AD9154_IRQ_STATUS3) + self.p("SYNC_TRIP1: %d, SYNC_WLIM1: %d, SYNC_ROTATE1: %d, " + "SYNC_LOCK1: %d, NCO_ALIGN1: %d, BLNKDONE1: %d, " + "PDPERR1: %d", + AD9154_SYNC_TRIP1_GET(x), AD9154_SYNC_WLIM1_GET(x), + AD9154_SYNC_ROTATE1_GET(x), AD9154_SYNC_LOCK1_GET(x), + AD9154_NCO_ALIGN1_GET(x), AD9154_BLNKDONE1_GET(x), + AD9154_PDPERR1_GET(x)) + x = self.ad9154.dac_read(AD9154_JESD_CHECKS) + self.p("ERR_INTSUPP: %d, ERR_SUBCLASS: %d, ERR_KUNSUPP: %d, " + "ERR_JESDBAD: %d, ERR_WINLIMIT: %d, ERR_DLYOVER: %d", + AD9154_ERR_INTSUPP_GET(x), AD9154_ERR_SUBCLASS_GET(x), + AD9154_ERR_KUNSUPP_GET(x), AD9154_ERR_JESDBAD_GET(x), + AD9154_ERR_WINLIMIT_GET(x), AD9154_ERR_DLYOVER_GET(x)) + + x = self.ad9154.dac_read(AD9154_DACPLLSTATUS) + self.p("DACPLL_LOCK: %d, VCO_CAL_PROGRESS: %d, CP_CAL_VALID: %d, " + "CP_OVERRANGE_L: %d, CP_OVERRANGE_H: %d", + AD9154_DACPLL_LOCK_GET(x), AD9154_VCO_CAL_PROGRESS_GET(x), + AD9154_CP_CAL_VALID_GET(x), AD9154_CP_OVERRANGE_L_GET(x), + AD9154_CP_OVERRANGE_H_GET(x)) + + x = self.ad9154.dac_read(AD9154_PLL_STATUS) + self.p("PLL_LOCK_RB: %d, CURRENTS_READY_RB: %d, " + "VCO_CAL_IN_PROGRESS_RB: %d, PLL_CAL_VALID_RB: %d, " + "PLL_OVERRANGE_L_RB: %d, PLL_OVERRANGE_H_RB: %d", + AD9154_SERDES_PLL_LOCK_RB_GET(x), + AD9154_SERDES_CURRENTS_READY_RB_GET(x), + AD9154_SERDES_VCO_CAL_IN_PROGRESS_RB_GET(x), + AD9154_SERDES_PLL_CAL_VALID_RB_GET(x), + AD9154_SERDES_PLL_OVERRANGE_L_RB_GET(x), + AD9154_SERDES_PLL_OVERRANGE_H_RB_GET(x)) + + self.p("CODEGRPSYNC: 0x%02x", self.ad9154.dac_read(AD9154_CODEGRPSYNCFLG)) + self.p("FRAMESYNC: 0x%02x", self.ad9154.dac_read(AD9154_FRAMESYNCFLG)) + self.p("GOODCHECKSUM: 0x%02x", self.ad9154.dac_read(AD9154_GOODCHKSUMFLG)) + self.p("INITIALLANESYNC: 0x%02x", self.ad9154.dac_read(AD9154_INITLANESYNCFLG)) + + x = self.ad9154.dac_read(AD9154_SYNC_LASTERR_H) + self.p("SYNC_LASTERR: 0x%04x", self.ad9154.dac_read(AD9154_SYNC_LASTERR_L) | + (AD9154_LASTERROR_H_GET(x) << 8)) + self.p("SYNC_LASTOVER: %d, SYNC_LASTUNDER: %d", + AD9154_LASTOVER_GET(x), AD9154_LASTUNDER_GET(x)) + x = self.ad9154.dac_read(AD9154_SYNC_STATUS) + self.p("SYNC_TRIP: %d, SYNC_WLIM: %d, SYNC_ROTATE: %d, " + "SYNC_LOCK: %d, SYNC_BUSY: %d", + AD9154_SYNC_TRIP_GET(x), AD9154_SYNC_WLIM_GET(x), + AD9154_SYNC_ROTATE_GET(x), AD9154_SYNC_LOCK_GET(x), + AD9154_SYNC_BUSY_GET(x)) + + self.p("LANE_FIFO_FULL: 0x%02x", self.ad9154.dac_read(AD9154_FIFO_STATUS_REG_0)) + self.p("LANE_FIFO_EMPTY: 0x%02x", self.ad9154.dac_read(AD9154_FIFO_STATUS_REG_1)) + self.p("DID_REG: 0x%02x", self.ad9154.dac_read(AD9154_DID_REG)) + self.p("BID_REG: 0x%02x", self.ad9154.dac_read(AD9154_BID_REG)) + self.p("SCR_L_REG: 0x%02x", self.ad9154.dac_read(AD9154_SCR_L_REG)) + self.p("F_REG: 0x%02x", self.ad9154.dac_read(AD9154_F_REG)) + self.p("K_REG: 0x%02x", self.ad9154.dac_read(AD9154_K_REG)) + self.p("M_REG: 0x%02x", self.ad9154.dac_read(AD9154_M_REG)) + self.p("CS_N_REG: 0x%02x", self.ad9154.dac_read(AD9154_CS_N_REG)) + self.p("NP_REG: 0x%02x", self.ad9154.dac_read(AD9154_NP_REG)) + self.p("S_REG: 0x%02x", self.ad9154.dac_read(AD9154_S_REG)) + self.p("HD_CF_REG: 0x%02x", self.ad9154.dac_read(AD9154_HD_CF_REG)) + self.p("RES1_REG: 0x%02x", self.ad9154.dac_read(AD9154_RES1_REG)) + self.p("RES2_REG: 0x%02x", self.ad9154.dac_read(AD9154_RES2_REG)) + self.p("LIDx_REG: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", + self.ad9154.dac_read(AD9154_LID0_REG), self.ad9154.dac_read(AD9154_LID1_REG), + self.ad9154.dac_read(AD9154_LID2_REG), self.ad9154.dac_read(AD9154_LID3_REG), + self.ad9154.dac_read(AD9154_LID4_REG), self.ad9154.dac_read(AD9154_LID5_REG), + self.ad9154.dac_read(AD9154_LID6_REG), self.ad9154.dac_read(AD9154_LID7_REG)) + self.p("CHECKSUMx_REG: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", + self.ad9154.dac_read(AD9154_CHECKSUM0_REG), self.ad9154.dac_read(AD9154_CHECKSUM1_REG), + self.ad9154.dac_read(AD9154_CHECKSUM2_REG), self.ad9154.dac_read(AD9154_CHECKSUM3_REG), + self.ad9154.dac_read(AD9154_CHECKSUM4_REG), self.ad9154.dac_read(AD9154_CHECKSUM5_REG), + self.ad9154.dac_read(AD9154_CHECKSUM6_REG), self.ad9154.dac_read(AD9154_CHECKSUM7_REG)) + self.p("COMPSUMx_REG: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", + self.ad9154.dac_read(AD9154_COMPSUM0_REG), self.ad9154.dac_read(AD9154_COMPSUM1_REG), + self.ad9154.dac_read(AD9154_COMPSUM2_REG), self.ad9154.dac_read(AD9154_COMPSUM3_REG), + self.ad9154.dac_read(AD9154_COMPSUM4_REG), self.ad9154.dac_read(AD9154_COMPSUM5_REG), + self.ad9154.dac_read(AD9154_COMPSUM6_REG), self.ad9154.dac_read(AD9154_COMPSUM7_REG)) + self.p("BADDISPARITY: 0x%02x", self.ad9154.dac_read(AD9154_BADDISPARITY)) + self.p("NITDISPARITY: 0x%02x", self.ad9154.dac_read(AD9154_NIT_W)) + self.p("UNEXPECTEDCONTROL: 0x%02x", self.ad9154.dac_read(AD9154_UNEXPECTEDCONTROL_W)) diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py new file mode 100644 index 000000000..76c8a6816 --- /dev/null +++ b/artiq/examples/phaser/startup_kernel.py @@ -0,0 +1,306 @@ +from artiq.experiment import * +from artiq.coredevice.ad9516_reg import * +from artiq.coredevice.ad9154_reg import * + + +class StartupKernel(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("led") + self.setattr_device("ad9154") + + @kernel + def run(self): + # ad9154 mode 2: + # M=4 converters + # L=4 lanes + # S=1 samples/converter and /frame + # F=2 octets/lane and /frame + # K=16 frames/multiframe (or 32) + # HD=0 high density + # N=16 bits/converter + # NB=16 bits/sample + # + # external clk=2000MHz + # pclock=250MHz + # fdata=500MHz + # fline=10GHz + # deviceclock_fpga=500MHz + # deviceclock_dac=2000MHz + self.core.reset() + self.ad9154.init() + self.clock_setup() + self.dac_setup() + + @kernel + def clock_setup(self): + # reset + self.ad9154.clock_write(AD9516_SERIAL_PORT_CONFIGURATION, + AD9516_SOFT_RESET | AD9516_SOFT_RESET_MIRRORED | + AD9516_LONG_INSTRUCTION | AD9516_LONG_INSTRUCTION_MIRRORED | + AD9516_SDO_ACTIVE | AD9516_SDO_ACTIVE_MIRRORED) + self.ad9154.clock_write(AD9516_SERIAL_PORT_CONFIGURATION, + AD9516_LONG_INSTRUCTION | AD9516_LONG_INSTRUCTION_MIRRORED | + AD9516_SDO_ACTIVE | AD9516_SDO_ACTIVE_MIRRORED) + if self.ad9154.clock_read(AD9516_PART_ID) != 0x41: + return + + # use clk input, dclk=clk/4 + self.ad9154.clock_write(AD9516_PFD_AND_CHARGE_PUMP, 1*AD9516_PLL_POWER_DOWN | + 0*AD9516_CHARGE_PUMP_MODE) + self.ad9154.clock_write(AD9516_VCO_DIVIDER, 2) + self.ad9154.clock_write(AD9516_INPUT_CLKS, 0*AD9516_SELECT_VCO_OR_CLK | + 0*AD9516_BYPASS_VCO_DIVIDER) + + self.ad9154.clock_write(AD9516_OUT0, 2*AD9516_OUT0_POWER_DOWN) + self.ad9154.clock_write(AD9516_OUT2, 2*AD9516_OUT2_POWER_DOWN) + self.ad9154.clock_write(AD9516_OUT3, 2*AD9516_OUT3_POWER_DOWN) + self.ad9154.clock_write(AD9516_OUT4, 2*AD9516_OUT4_POWER_DOWN) + self.ad9154.clock_write(AD9516_OUT5, 2*AD9516_OUT5_POWER_DOWN) + self.ad9154.clock_write(AD9516_OUT8, 1*AD9516_OUT8_POWER_DOWN) + + # DAC deviceclk, clk/1 + self.ad9154.clock_write(AD9516_DIVIDER_0_2, AD9516_DIVIDER_0_DIRECT_TO_OUTPUT) + self.ad9154.clock_write(AD9516_OUT1, 0*AD9516_OUT1_POWER_DOWN | + 2*AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE) + + # FPGA deviceclk, dclk/1 + self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_1 | + AD9516_DIVIDER_4_BYPASS_2) + self.ad9154.clock_write(AD9516_DIVIDER_4_4, 1*AD9516_DIVIDER_4_DCCOFF) + self.ad9154.clock_write(AD9516_OUT9, 1*AD9516_OUT9_LVDS_OUTPUT_CURRENT | + 2*AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY | + 0*AD9516_OUT9_SELECT_LVDS_CMOS) + + # sysref f_data*S/(K*F), dclk/32 + self.ad9154.clock_write(AD9516_DIVIDER_3_0, 15*AD9516_DIVIDER_3_HIGH_CYCLES_1 | + 15*AD9516_DIVIDER_3_LOW_CYCLES_1) + self.ad9154.clock_write(AD9516_DIVIDER_3_1, 0*AD9516_DIVIDER_3_PHASE_OFFSET_1 | + 0*AD9516_DIVIDER_3_PHASE_OFFSET_2) + self.ad9154.clock_write(AD9516_DIVIDER_3_3, 0*AD9516_DIVIDER_3_NOSYNC | + 0*AD9516_DIVIDER_3_BYPASS_1 | 1*AD9516_DIVIDER_3_BYPASS_2) + self.ad9154.clock_write(AD9516_DIVIDER_3_4, 1*AD9516_DIVIDER_3_DCCOFF) + self.ad9154.clock_write(AD9516_OUT6, 1*AD9516_OUT6_LVDS_OUTPUT_CURRENT | + 2*AD9516_OUT6_LVDS_CMOS_OUTPUT_POLARITY | + 0*AD9516_OUT6_SELECT_LVDS_CMOS) + self.ad9154.clock_write(AD9516_OUT7, 1*AD9516_OUT7_LVDS_OUTPUT_CURRENT | + 2*AD9516_OUT7_LVDS_CMOS_OUTPUT_POLARITY | + 0*AD9516_OUT7_SELECT_LVDS_CMOS) + + self.ad9154.clock_write(AD9516_UPDATE_ALL_REGISTERS, 1) + + @kernel + def dac_setup(self): + # reset + self.ad9154.dac_write(AD9154_SPI_INTFCONFA, AD9154_SOFTRESET_SET(1) | + AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1)) + self.ad9154.dac_write(AD9154_SPI_INTFCONFA, + AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1)) + if ((self.ad9154.dac_read(AD9154_PRODIDH) << 8) | + self.ad9154.dac_read(AD9154_PRODIDL) != 0x9154): + return + + self.ad9154.dac_write(AD9154_PWRCNTRL0, + AD9154_PD_DAC0_SET(0) | AD9154_PD_DAC1_SET(0) | + AD9154_PD_DAC2_SET(0) | AD9154_PD_DAC3_SET(0) | + AD9154_PD_BG_SET(0)) + self.ad9154.dac_write(AD9154_TXENMASK1, AD9154_DACA_MASK_SET(0) | + AD9154_DACB_MASK_SET(0)) # TX not controlled by TXEN pins + self.ad9154.dac_write(AD9154_CLKCFG0, + AD9154_REF_CLKDIV_EN_SET(0) | AD9154_RF_SYNC_EN_SET(1) | + AD9154_DUTY_EN_SET(1) | AD9154_PD_CLK_REC_SET(0) | + AD9154_PD_SERDES_PCLK_SET(0) | AD9154_PD_CLK_DIG_SET(0) | + AD9154_PD_CLK23_SET(0) | AD9154_PD_CLK01_SET(0)) + self.ad9154.dac_write(AD9154_DACPLLCNTRL, + AD9154_ENABLE_DACPLL_SET(0) | AD9154_RECAL_DACPLL_SET(0)) + self.ad9154.dac_write(AD9154_SYSREF_ACTRL0, # jesd204b subclass 1 + AD9154_HYS_CNTRL1_SET(0) | AD9154_SYSREF_RISE_SET(0) | + AD9154_HYS_ON_SET(0) | AD9154_PD_SYSREF_BUFFER_SET(0)) + + self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_0, 0x8b) # magic + self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_1, 0x01) # magic + self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_2, 0x01) # magic + + self.ad9154.dac_write(AD9154_SPI_PAGEINDX, 0x3) # A and B dual + + self.ad9154.dac_write(AD9154_INTERP_MODE, 3) # 4x + 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_DATAPATH_CTRL, + AD9154_I_TO_Q_SET(0) | AD9154_SEL_SIDEBAND_SET(0) | + AD9154_MODULATION_TYPE_SET(0) | AD9154_PHASE_ADJ_ENABLE_SET(0) | + AD9154_DIG_GAIN_ENABLE_SET(0) | AD9154_INVSINC_ENABLE_SET(0)) + self.ad9154.dac_write(AD9154_IDAC_DIG_GAIN0, 0x00) + self.ad9154.dac_write(AD9154_IDAC_DIG_GAIN1, 0x8) + self.ad9154.dac_write(AD9154_QDAC_DIG_GAIN0, 0x00) + self.ad9154.dac_write(AD9154_QDAC_DIG_GAIN1, 0x8) + self.ad9154.dac_write(AD9154_DC_OFFSET_CTRL, 0) + self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_1PART0, 0x00) + self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_1PART1, 0x00) + self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_2PART, 0x00) + self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_1PART0, 0x00) + self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_1PART1, 0x00) + self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_2PART, 0x00) + self.ad9154.dac_write(AD9154_PHASE_ADJ0, 0) + self.ad9154.dac_write(AD9154_PHASE_ADJ1, 0) + self.ad9154.dac_write(AD9154_GROUP_DLY, AD9154_COARSE_GROUP_DELAY_SET(0x8) | + AD9154_GROUP_DELAY_RESERVED_SET(0x8)) + self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_BYP, + AD9154_GROUPCOMP_BYPQ_SET(1) | + AD9154_GROUPCOMP_BYPI_SET(1)) + self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_I, 0) + self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_Q, 0) + self.ad9154.dac_write(AD9154_PDP_AVG_TIME, AD9154_PDP_ENABLE_SET(0)) + + self.ad9154.dac_write(AD9154_MASTER_PD, 0) + self.ad9154.dac_write(AD9154_PHY_PD, 0x0f) # power down lanes 0-3 + self.ad9154.dac_write(AD9154_GENERIC_PD, + AD9154_PD_SYNCOUT0B_SET(0) | + AD9154_PD_SYNCOUT1B_SET(1)) + self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_0, + AD9154_LINK_EN_SET(0x0) | AD9154_LINK_PAGE_SET(0) | + AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0)) + self.ad9154.dac_write(AD9154_ILS_DID, 0x00) # device id + self.ad9154.dac_write(AD9154_ILS_BID, 0x00) # band id + self.ad9154.dac_write(AD9154_ILS_LID0, 0x00) # lane id + self.ad9154.dac_write(AD9154_ILS_SCR_L, AD9154_L_1_SET(4 - 1) | AD9154_SCR_SET(1)) + self.ad9154.dac_write(AD9154_ILS_F, 2 - 1) + self.ad9154.dac_write(AD9154_ILS_K, 16 - 1) + self.ad9154.dac_write(AD9154_ILS_M, 4 - 1) + self.ad9154.dac_write(AD9154_ILS_CS_N, AD9154_N_1_SET(16 - 1) | AD9154_CS_SET(0)) + self.ad9154.dac_write(AD9154_ILS_NP, AD9154_NP_1_SET(16 - 1) | + AD9154_SUBCLASSV_SET(1)) + self.ad9154.dac_write(AD9154_ILS_S, AD9154_S_1_SET(1 - 1) | AD9154_JESDV_SET(1)) + self.ad9154.dac_write(AD9154_ILS_HD_CF, AD9154_HD_SET(0) | AD9154_CF_SET(0)) + self.ad9154.dac_write(AD9154_ILS_CHECKSUM, + 0x00 + 0x00 + 0x00 + 1 + (4 - 1) + # DID BID LID SCR L + (2 - 1) + (16 - 1) + (4 - 1) + (16 - 1) + # F K M N + 1 + (16 - 1) + 1 + (1 - 1) + 0 # SUBC NP JESDV S HD + ) + self.ad9154.dac_write(AD9154_LANEDESKEW, 0xf0) + for i in range(8): + self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_DIS_SET(0) | + AD9154_DISABLE_ERR_CNTR_DIS_SET(0) | + AD9154_RST_ERR_CNTR_DIS_SET(1) | AD9154_LANE_ADDR_DIS_SET(i)) + self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_DIS_SET(0) | + AD9154_DISABLE_ERR_CNTR_DIS_SET(0) | + AD9154_RST_ERR_CNTR_DIS_SET(0) | AD9154_LANE_ADDR_DIS_SET(i)) + self.ad9154.dac_write(AD9154_NIT_W, AD9154_RST_IRQ_NIT_SET(0) | + AD9154_DISABLE_ERR_CNTR_NIT_SET(0) | + AD9154_RST_ERR_CNTR_NIT_SET(1) | AD9154_LANE_ADDR_NIT_SET(i)) + self.ad9154.dac_write(AD9154_NIT_W, AD9154_RST_IRQ_NIT_SET(0) | + AD9154_DISABLE_ERR_CNTR_NIT_SET(0) | + AD9154_RST_ERR_CNTR_NIT_SET(0) | AD9154_LANE_ADDR_NIT_SET(i)) + self.ad9154.dac_write(AD9154_UNEXPECTEDCONTROL_W, AD9154_RST_IRQ_UCC_SET(0) | + AD9154_DISABLE_ERR_CNTR_UCC_SET(0) | + AD9154_RST_ERR_CNTR_UCC_SET(1) | AD9154_LANE_ADDR_UCC_SET(i)) + self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_UCC_SET(0) | + AD9154_DISABLE_ERR_CNTR_UCC_SET(0) | + AD9154_RST_ERR_CNTR_UCC_SET(0) | AD9154_LANE_ADDR_UCC_SET(i)) + self.ad9154.dac_write(AD9154_CTRLREG1, 2) # F + self.ad9154.dac_write(AD9154_CTRLREG2, AD9154_ILAS_MODE_SET(0) | + AD9154_THRESHOLD_MASK_EN_SET(0)) + self.ad9154.dac_write(AD9154_KVAL, 1) # 4*K multiframes during ILAS + self.ad9154.dac_write(AD9154_LANEENABLE, 0xf0) + + self.ad9154.dac_write(AD9154_TERM_BLK1_CTRLREG0, 1) + self.ad9154.dac_write(AD9154_TERM_BLK2_CTRLREG0, 1) + self.ad9154.dac_write(AD9154_SERDES_SPI_REG, 1) + self.ad9154.dac_write(AD9154_CDR_OPERATING_MODE_REG_0, + AD9154_CDR_OVERSAMP_SET(0) | AD9154_CDR_RESERVED_SET(0x2) | + AD9154_ENHALFRATE_SET(1)) + self.ad9154.dac_write(AD9154_CDR_RESET, 0) + self.ad9154.dac_write(AD9154_CDR_RESET, 1) + self.ad9154.dac_write(AD9154_REF_CLK_DIVIDER_LDO, + AD9154_SPI_CDR_OVERSAMP_SET(0x0) | + AD9154_SPI_LDO_BYPASS_FILT_SET(1) | + AD9154_SPI_LDO_REF_SEL_SET(0)) + self.ad9154.dac_write(AD9154_LDO_FILTER_1, 0x62) # magic + self.ad9154.dac_write(AD9154_LDO_FILTER_2, 0xc9) # magic + self.ad9154.dac_write(AD9154_LDO_FILTER_3, 0x0e) # magic + self.ad9154.dac_write(AD9154_CP_CURRENT_SPI, + AD9154_SPI_CP_CURRENT_SET(0x12) | + AD9154_SPI_SERDES_LOGEN_POWER_MODE_SET(0)) + self.ad9154.dac_write(AD9154_VCO_LDO, 0x7b) # magic + self.ad9154.dac_write(AD9154_PLL_RD_REG, + AD9154_SPI_SERDES_LOGEN_PD_CORE_SET(0) | + AD9154_SPI_SERDES_LDO_PD_SET(0) | AD9154_SPI_SYN_PD_SET(0) | + AD9154_SPI_VCO_PD_ALC_SET(0) | AD9154_SPI_VCO_PD_PTAT_SET(0) | + AD9154_SPI_VCO_PD_SET(0)) + self.ad9154.dac_write(AD9154_ALC_VARACTOR, + AD9154_SPI_VCO_VARACTOR_SET(0x9) | + AD9154_SPI_INIT_ALC_VALUE_SET(0x8)) + self.ad9154.dac_write(AD9154_VCO_OUTPUT, + AD9154_SPI_VCO_OUTPUT_LEVEL_SET(0xc) | + AD9154_SPI_VCO_OUTPUT_RESERVED_SET(0x4)) + self.ad9154.dac_write(AD9154_CP_CONFIG, + AD9154_SPI_CP_TEST_SET(0) | + AD9154_SPI_CP_CAL_EN_SET(1) | + AD9154_SPI_CP_FORCE_CALBITS_SET(0) | + AD9154_SPI_CP_OFFSET_OFF_SET(0) | + AD9154_SPI_CP_ENABLE_MACHINE_SET(1) | + AD9154_SPI_CP_DITHER_MODE_SET(0) | + AD9154_SPI_CP_HALF_VCO_CAL_CLK_SET(0)) + self.ad9154.dac_write(AD9154_VCO_BIAS_1, + AD9154_SPI_VCO_BIAS_REF_SET(0x3) | + AD9154_SPI_VCO_BIAS_TCF_SET(0x3)) + self.ad9154.dac_write(AD9154_VCO_BIAS_2, + AD9154_SPI_PRESCALE_BIAS_SET(0x1) | + AD9154_SPI_LAST_ALC_EN_SET(1) | + AD9154_SPI_PRESCALE_BYPASS_R_SET(0x1) | + AD9154_SPI_VCO_COMP_BYPASS_BIASR_SET(0) | + AD9154_SPI_VCO_BYPASS_DAC_R_SET(0)) + self.ad9154.dac_write(AD9154_VCO_PD_OVERRIDES, + AD9154_SPI_VCO_PD_OVERRIDE_VCO_BUF_SET(0) | + AD9154_SPI_VCO_PD_OVERRIDE_CAL_TCF_SET(1) | + AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_TCF_SET(0) | + AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_SET(0)) + self.ad9154.dac_write(AD9154_VCO_CAL, + AD9154_SPI_FB_CLOCK_ADV_SET(0x2) | + AD9154_SPI_VCO_CAL_COUNT_SET(0x3) | + AD9154_SPI_VCO_CAL_ALC_WAIT_SET(0) | + AD9154_SPI_VCO_CAL_EN_SET(1)) + self.ad9154.dac_write(AD9154_CP_LEVEL_DETECT, + AD9154_SPI_CP_LEVEL_THRESHOLD_HIGH_SET(0x2) | + AD9154_SPI_CP_LEVEL_THRESHOLD_LOW_SET(0x5) | + AD9154_SPI_CP_LEVEL_DET_PD_SET(0)) + self.ad9154.dac_write(AD9154_VCO_VARACTOR_CTRL_0, + AD9154_SPI_VCO_VARACTOR_OFFSET_SET(0xe) | + AD9154_SPI_VCO_VARACTOR_REF_TCF_SET(0x7)) + self.ad9154.dac_write(AD9154_VCO_VARACTOR_CTRL_1, + AD9154_SPI_VCO_VARACTOR_REF_SET(0x6)) + # ensure link is txing + self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL, + AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(1)) + self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL, + AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(0)) + self.ad9154.dac_write(AD9154_EQ_BIAS_REG, AD9154_EQ_BIAS_RESERVED_SET(0x22) | + AD9154_EQ_POWER_MODE_SET(1)) + + self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_1, 1) # subclass 1 + self.ad9154.dac_write(AD9154_LMFC_DELAY_0, 0) + self.ad9154.dac_write(AD9154_LMFC_DELAY_1, 0) + self.ad9154.dac_write(AD9154_LMFC_VAR_0, 0x0a) # receive buffer delay + self.ad9154.dac_write(AD9154_LMFC_VAR_1, 0x0a) + self.ad9154.dac_write(AD9154_SYNC_ERRWINDOW, 0) # +- 1/2 DAC clock + self.ad9154.dac_write(AD9154_SYNC_CONTROL, + AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(0) | + AD9154_SYNCARM_SET(0)) + self.ad9154.dac_write(AD9154_SYNC_CONTROL, + AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(1) | + AD9154_SYNCARM_SET(0)) + self.ad9154.dac_write(AD9154_SYNC_CONTROL, + AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(1) | + AD9154_SYNCARM_SET(1)) + self.ad9154.dac_write(AD9154_XBAR_LN_0_1, + AD9154_LOGICAL_LANE0_SRC_SET(7) | AD9154_LOGICAL_LANE1_SRC_SET(6)) + self.ad9154.dac_write(AD9154_XBAR_LN_2_3, + AD9154_LOGICAL_LANE2_SRC_SET(5) | AD9154_LOGICAL_LANE3_SRC_SET(4)) + self.ad9154.dac_write(AD9154_XBAR_LN_4_5, + AD9154_LOGICAL_LANE4_SRC_SET(0) | AD9154_LOGICAL_LANE5_SRC_SET(0)) + self.ad9154.dac_write(AD9154_XBAR_LN_6_7, + AD9154_LOGICAL_LANE6_SRC_SET(0) | AD9154_LOGICAL_LANE7_SRC_SET(0)) + self.ad9154.dac_write(AD9154_JESD_BIT_INVERSE_CTRL, 0x00) + self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_0, + AD9154_LINK_EN_SET(0x1) | AD9154_LINK_PAGE_SET(0) | + AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0)) diff --git a/artiq/gateware/dsp/__init__.py b/artiq/gateware/dsp/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/artiq/gateware/dsp/accu.py b/artiq/gateware/dsp/accu.py new file mode 100644 index 000000000..6e8776476 --- /dev/null +++ b/artiq/gateware/dsp/accu.py @@ -0,0 +1,112 @@ +from migen import * +from misoc.interconnect.stream import Endpoint + + +class Accu(Module): + def __init__(self, width, meta=[]): + self.i = Endpoint([("p", width), ("f", width), ("clr", 1)]) + self.o = Endpoint([("z", width)]) + self.latency = 1 + + ### + + f = Signal.like(self.i.f) + p = Signal.like(self.i.p) + self.comb += self.i.ack.eq(~self.o.stb | self.o.ack) + self.sync += [ + If(self.o.ack, + self.o.stb.eq(0), + ), + If(self.i.ack, + self.o.stb.eq(1), + If(self.i.stb, + self.o.z.eq(self.i.p + Mux(self.i.clr, 0, self.o.z + p)), + f.eq(self.i.f), + p.eq(self.i.f - self.i.p), + ).Else( + self.o.z.eq(self.o.z + f), + ) + ) + ] + + +class MCM(Module): + def __init__(self, width, constants): + n = len(constants) + self.i = i = Signal(width) + self.o = o = [Signal.like(self.i) for i in range(n)] + + ### + + # TODO: improve MCM + assert range(n) == constants + assert n <= 9 + + if n > 0: + self.comb += o[0].eq(0) + if n > 1: + self.comb += o[1].eq(i) + if n > 2: + self.comb += o[2].eq(i << 1) + if n > 3: + self.comb += o[3].eq(i + (i << 1)) + if n > 4: + self.comb += o[4].eq(i << 2) + if n > 5: + self.comb += o[5].eq(i + (i << 2)) + if n > 6: + self.comb += o[6].eq(o[3] << 1) + if n > 7: + self.comb += o[7].eq((i << 3) - i) + if n > 8: + self.comb += o[8].eq(i << 3) + + +class PhasedAccu(Module): + def __init__(self, width, parallelism=8): + self.i = Endpoint([("p", width), ("f", width), ("clr", 1)]) + self.o = Endpoint([("z{}".format(i), width) for i in + range(parallelism)]) + self.parallelism = parallelism + self.latency = 2 + + ### + + a = MCM(width, range(parallelism + 1)) + self.submodules += a + z = [Signal(width) for i in range(parallelism)] + o = self.o.payload.flatten() + load = Signal() + clr = Signal() + p = Signal.like(self.i.p) + f = Signal.like(self.i.f) + fp = Signal.like(self.i.f) + self.comb += [ + self.i.ack.eq(self.o.ack), + a.i.eq(self.i.f), + ] + + self.sync += [ + If(self.o.ack, + self.o.stb.eq(0), + ), + If(~self.o.stb | self.o.ack, + self.o.stb.eq(1), + If(load, + load.eq(0), + [oi.eq(Mux(clr, 0, o[0] + fp) + zi) + for oi, zi in zip(o, z)], + fp.eq(f), + ).Else( + [oi.eq(oi + fp) for oi in o], + ), + ), + If(self.i.stb & self.i.ack, + [zi.eq(self.i.p - Mux(self.i.clr, 0, p) + aoi) + for zi, aoi in zip(z, a.o)], + clr.eq(self.i.clr), + p.eq(self.i.p), + f.eq(a.o[parallelism]), + load.eq(1), + ), + ] diff --git a/artiq/gateware/dsp/cordic.py b/artiq/gateware/dsp/cordic.py new file mode 100644 index 000000000..f09ca5031 --- /dev/null +++ b/artiq/gateware/dsp/cordic.py @@ -0,0 +1,358 @@ +# Copyright 2014-2015 Robert Jordens +# +# This file is part of redpid. +# +# redpid is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# redpid is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with redpid. If not, see . + +from math import atan, atanh, log, sqrt, pi + +from migen import * + + +class TwoQuadrantCordic(Module): + """Coordinate rotation digital computer + + Trigonometric, and arithmetic functions implemented using + additions/subtractions and shifts. + + http://eprints.soton.ac.uk/267873/1/tcas1_cordic_review.pdf + + http://www.andraka.com/files/crdcsrvy.pdf + + http://zatto.free.fr/manual/Volder_CORDIC.pdf + + The way the CORDIC is executed is controlled by `eval_mode`. + If `"iterative"` the stages are iteratively evaluated, one per clock + cycle. This mode uses the least amount of registers, but has the + lowest throughput and highest latency. If `"pipelined"` all stages + are executed in every clock cycle but separated by registers. This + mode has full throughput but uses many registers and has large + latency. If `"combinatorial"`, there are no registers, throughput is + maximal and latency is zero. `"pipelined"` and `"combinatorial"` use + the same number of shifters and adders. + + The type of trigonometric/arithmetic function is determined by + `cordic_mode` and `func_mode`. :math:`g` is the gain of the CORDIC. + + * rotate-circular: rotate the vector `(xi, yi)` by an angle `zi`. + Used to calculate trigonometric functions, `sin(), cos(), + tan() = sin()/cos()`, or to perform polar-to-cartesian coordinate + transformation: + + .. math:: + x_o = g \\cos(z_i) x_i - g \\sin(z_i) y_i + + y_o = g \\sin(z_i) x_i + g \\cos(z_i) y_i + + * vector-circular: determine length and angle of the vector + `(xi, yi)`. Used to calculate `arctan(), sqrt()` or + to perform cartesian-to-polar transformation: + + .. math:: + x_o = g\\sqrt{x_i^2 + y_i^2} + + z_o = z_i + \\tan^{-1}(y_i/x_i) + + * rotate-hyperbolic: hyperbolic functions of `zi`. Used to + calculate hyperbolic functions, `sinh, cosh, tanh = cosh/sinh, + exp = cosh + sinh`: + + .. math:: + x_o = g \\cosh(z_i) x_i + g \\sinh(z_i) y_i + + y_o = g \\sinh(z_i) x_i + g \\cosh(z_i) z_i + + * vector-hyperbolic: natural logarithm `ln(), arctanh()`, and + `sqrt()`. Use `x_i = a + b` and `y_i = a - b` to obtain `2* + sqrt(a*b)` and `ln(a/b)/2`: + + .. math:: + x_o = g\\sqrt{x_i^2 - y_i^2} + + z_o = z_i + \\tanh^{-1}(y_i/x_i) + + * rotate-linear: multiply and accumulate (not a very good + multiplier implementation): + + .. math:: + y_o = g(y_i + x_i z_i) + + * vector-linear: divide and accumulate: + + .. math:: + z_o = g(z_i + y_i/x_i) + + Parameters + ---------- + width : int + Bit width of the input and output signals. Defaults to 16. Input + and output signals are signed. + widthz : int + Bit with of `zi` and `zo`. Defaults to the `width`. + stages : int or None + Number of CORDIC incremental rotation stages. Defaults to + `width + min(1, guard)`. + guard : int or None + Add guard bits to the intermediate signals. If `None`, + defaults to `guard = log2(width)` which guarantees accuracy + to `width` bits. + eval_mode : str, {"iterative", "pipelined", "combinatorial"} + cordic_mode : str, {"rotate", "vector"} + func_mode : str, {"circular", "linear", "hyperbolic"} + Evaluation and arithmetic mode. See above. + + Attributes + ---------- + xi, yi, zi : Signal(width), in + Input values, signed. + xo, yo, zo : Signal(width), out + Output values, signed. + new_out : Signal(1), out + Asserted if output values are freshly updated in the current + cycle. + new_in : Signal(1), out + Asserted if new input values are being read in the next cycle. + zmax : float + `zi` and `zo` normalization factor. Floating point `zmax` + corresponds to `1<<(widthz - 1)`. `x` and `y` are scaled such + that floating point `1` corresponds to `1<<(width - 1)`. + gain : float + Cumulative, intrinsic gain and scaling factor. In circular mode + `sqrt(xi**2 + yi**2)` should be no larger than `2**(width - 1)/gain` + to prevent overflow. Additionally, in hyperbolic and linear mode, + the operation itself can cause overflow. + interval : int + Output interval in clock cycles. Inverse throughput. + latency : int + Input-to-output latency. The result corresponding to the inputs + appears at the outputs `latency` cycles later. + + Notes + ----- + + Each stage `i` in the CORDIC performs the following operation: + + .. math:: + x_{i+1} = x_i - m d_i y_i r^{-s_{m,i}}, + + y_{i+1} = y_i + d_i x_i r^{-s_{m,i}}, + + z_{i+1} = z_i - d_i a_{m,i}, + + where: + + * :math:`d_i`: clockwise or counterclockwise, determined by + `sign(z_i)` in rotate mode or `sign(-y_i)` in vector mode. + + * :math:`r`: radix of the number system (2) + + * :math:`m`: 1: circular, 0: linear, -1: hyperbolic + + * :math:`s_{m,i}`: non decreasing integer shift sequence + + * :math:`a_{m,i}`: elemetary rotation angle: :math:`a_{m,i} = + \\tan^{-1}(\\sqrt{m} s_{m,i})/\\sqrt{m}`. + """ + def __init__(self, width=16, widthz=None, stages=None, guard=0, + eval_mode="iterative", cordic_mode="rotate", + func_mode="circular"): + # validate parameters + assert eval_mode in ("combinatorial", "pipelined", "iterative") + assert cordic_mode in ("rotate", "vector") + assert func_mode in ("circular", "linear", "hyperbolic") + self.cordic_mode = cordic_mode + self.func_mode = func_mode + if guard is None: + # guard bits to guarantee "width" accuracy + guard = int(log(width)/log(2)) + if widthz is None: + widthz = width + if stages is None: + stages = width + min(1, guard) # cuts error below LSB + + # input output interface + self.xi = Signal((width, True)) + self.yi = Signal((width, True)) + self.zi = Signal((widthz, True)) + self.xo = Signal((width, True)) + self.yo = Signal((width, True)) + self.zo = Signal((widthz, True)) + self.new_in = Signal() + self.new_out = Signal() + + ### + + a, s, self.zmax, self.gain = self._constants(stages, widthz + guard) + stages = len(a) # may have increased due to repetitions + + if eval_mode == "iterative": + num_sig = 3 + self.interval = stages + 1 + self.latency = stages + 2 + else: + num_sig = stages + 1 + self.interval = 1 + if eval_mode == "pipelined": + self.latency = stages + else: # combinatorial + self.latency = 0 + + # inter-stage signals + x = [Signal((width + guard, True)) for i in range(num_sig)] + y = [Signal((width + guard, True)) for i in range(num_sig)] + z = [Signal((widthz + guard, True)) for i in range(num_sig)] + + # hook up inputs and outputs to the first and last inter-stage + # signals + self.comb += [ + x[0].eq(self.xi << guard), + y[0].eq(self.yi << guard), + z[0].eq(self.zi << guard), + self.xo.eq(x[-1] >> guard), + self.yo.eq(y[-1] >> guard), + self.zo.eq(z[-1] >> guard), + ] + + if eval_mode == "iterative": + # We afford one additional iteration for in/out. + i = Signal(max=stages + 1) + self.comb += [ + self.new_in.eq(i == stages), + self.new_out.eq(i == 1), + ] + ai = Signal((widthz + guard, True)) + self.sync += ai.eq(Array(a)[i]) + if range(stages) == s: + si = i - 1 # shortcut if no stage repetitions + else: + si = Signal(max=stages + 1) + self.sync += si.eq(Array(s)[i]) + xi, yi, zi = x[1], y[1], z[1] + self.sync += [ + self._stage(xi, yi, zi, xi, yi, zi, si, ai), + i.eq(i + 1), + If(i == stages, + i.eq(0), + ), + If(i == 0, + x[2].eq(xi), y[2].eq(yi), z[2].eq(zi), + xi.eq(x[0]), yi.eq(y[0]), zi.eq(z[0]), + ) + ] + else: + self.comb += [ + self.new_out.eq(1), + self.new_in.eq(1), + ] + for i, si in enumerate(s): + stmt = self._stage(x[i], y[i], z[i], + x[i + 1], y[i + 1], z[i + 1], + si, a[i]) + if eval_mode == "pipelined": + self.sync += stmt + else: # combinatorial + self.comb += stmt + + def _constants(self, stages, bits): + if self.func_mode == "circular": + s = range(stages) + a = [atan(2**-i) for i in s] + g = [sqrt(1 + 2**(-2*i)) for i in s] + #zmax = sum(a) + # use pi anyway as the input z can cause overflow + # and we need the range for quadrant mapping + zmax = pi + elif self.func_mode == "linear": + s = range(stages) + a = [2**-i for i in s] + g = [1 for i in s] + #zmax = sum(a) + # use 2 anyway as this simplifies a and scaling + zmax = 2. + else: # hyperbolic + s = [] + # need to repeat some stages: + j = 4 + for i in range(stages): + if i == j: + s.append(j) + j = 3*j + 1 + s.append(i + 1) + a = [atanh(2**-i) for i in s] + g = [sqrt(1 - 2**(-2*i)) for i in s] + zmax = sum(a)*2 + # round here helps the width=2**i - 1 case but hurts the + # important width=2**i case + cast = int + if log(bits)/log(2) % 1: + cast = round + a = [cast(ai*2**(bits - 1)/zmax) for ai in a] + gain = 1. + for gi in g: + gain *= gi + return a, s, zmax, gain + + def _stage(self, xi, yi, zi, xo, yo, zo, i, ai): + dir = Signal() + if self.cordic_mode == "rotate": + self.comb += dir.eq(zi < 0) + else: # vector + self.comb += dir.eq(yi >= 0) + dx = yi >> i + dy = xi >> i + dz = ai + if self.func_mode == "linear": + dx = 0 + elif self.func_mode == "hyperbolic": + dx = -dx + stmt = [ + xo.eq(xi + Mux(dir, dx, -dx)), + yo.eq(yi + Mux(dir, -dy, dy)), + zo.eq(zi + Mux(dir, dz, -dz)) + ] + return stmt + + +class Cordic(TwoQuadrantCordic): + """Four-quadrant CORDIC + + Same as :class:`TwoQuadrantCordic` but with support and convergence + for `abs(zi) > pi/2 in circular rotate mode or `xi < 0` in circular + vector mode. + """ + def __init__(self, **kwargs): + TwoQuadrantCordic.__init__(self, **kwargs) + if self.func_mode != "circular": + return # no need to remap quadrants + + cxi, cyi, czi = self.xi, self.yi, self.zi + self.xi = xi = Signal.like(cxi) + self.yi = yi = Signal.like(cyi) + self.zi = zi = Signal.like(czi) + + ### + + q = Signal() + if self.cordic_mode == "rotate": + self.comb += q.eq(zi[-2] ^ zi[-1]) + else: # vector + self.comb += q.eq(xi < 0) + self.comb += [ + If(q, + Cat(cxi, cyi, czi).eq( + Cat(-xi, -yi, zi + (1 << len(zi) - 1))) + ).Else( + Cat(cxi, cyi, czi).eq(Cat(xi, yi, zi)) + ) + ] diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py new file mode 100644 index 000000000..f39b3603a --- /dev/null +++ b/artiq/gateware/dsp/sawg.py @@ -0,0 +1,67 @@ +from migen import * +from misoc.interconnect.stream import Endpoint + +from .cordic import Cordic +from .accu import PhasedAccu +from .tools import eqh + + +class DDSFast(Module): + def __init__(self, width, parallelism=4): + a_width = width + p_width = width + f_width = 2*width + + self.o = [Signal((width, True)) for i in range(parallelism)] + + self.width = width + self.parallelism = parallelism + self.latency = 1 # will be accumulated + + q = PhasedAccu(f_width, parallelism) + self.submodules += q + self.latency += q.latency + + self.a = Endpoint([("a", a_width)]) + self.f = Endpoint([("f", f_width)]) + self.p = Endpoint([("p", p_width)]) + self.i = [self.a, self.f, self.p] + + ### + + a = Signal.like(self.a.a) + self.sync += [ + If(self.a.stb, + a.eq(self.a.a) + ), + If(self.f.stb, + eqh(q.i.f, self.f.f) + ), + If(self.p.stb, + eqh(q.i.p, self.p.p) + ), + q.i.stb.eq(self.f.stb | self.p.stb), + ] + self.comb += [ + self.a.ack.eq(1), + self.f.ack.eq(1), + self.p.ack.eq(1), + q.o.ack.eq(1), + q.i.clr.eq(0), + ] + + c = [] + for i in range(parallelism): + ci = Cordic(width=width, widthz=p_width, + guard=None, eval_mode="pipelined") + self.submodules += ci + c.append(ci) + qoi = getattr(q.o, "z{}".format(i)) + self.comb += [ + eqh(ci.xi, a), + ci.yi.eq(0), + eqh(ci.zi, qoi), + eqh(self.o[i], ci.xo), + ] + self.latency += c[0].latency + self.gain = c[0].gain diff --git a/artiq/gateware/dsp/tools.py b/artiq/gateware/dsp/tools.py new file mode 100644 index 000000000..947745242 --- /dev/null +++ b/artiq/gateware/dsp/tools.py @@ -0,0 +1,50 @@ +from migen import * + + +def set_dict(e, **k): + for k, v in k.items(): + if isinstance(v, dict): + yield from set_dict(getattr(e, k), **v) + else: + yield getattr(e, k).eq(v) + + +def xfer(dut, **kw): + ep = [] + for e, v in kw.items(): + e = getattr(dut, e) + yield from set_dict(e, **v) + ep.append(e) + for e in ep: + yield e.stb.eq(1) + while ep: + yield + for e in ep[:]: + if hasattr(e, "busy") and (yield e.busy): + raise ValueError(e, "busy") + if not hasattr(e, "ack") or (yield e.ack): + yield e.stb.eq(0) + ep.remove(e) + + +def eqh(a, b): + return a[-len(b):].eq(b[-len(a):]) + + +def szip(*iters): + active = {it: None for it in iters} + while active: + for it in list(active): + while True: + try: + val = it.send(active[it]) + except StopIteration: + del active[it] + break + if val is None: + break + else: + active[it] = (yield val) + val = (yield None) + for it in active: + active[it] = val diff --git a/artiq/gateware/phaser.py b/artiq/gateware/phaser.py new file mode 100644 index 000000000..d72e6c153 --- /dev/null +++ b/artiq/gateware/phaser.py @@ -0,0 +1,71 @@ +from migen.build.generic_platform import * + + +fmc_adapter_io = [ + ("ad9154_spi", 0, + # AD9154 should give control of SPI to FMC when USB cable is unplugged, + # It's the case, but the PIC18F24J50 is introducing noise on SPI SCK + # (???) To workaround that, add 2 jumpers: + # - on XP1, between pin 5 and 6 (will keep the PIC in reset) + # - on JP3 (will force output enable on FXLA108) + Subsignal("clk", Pins("HPC:LA03_P")), + Subsignal("cs_n", Pins("HPC:LA04_N", "HPC:LA05_P")), + Subsignal("mosi", Pins("HPC:LA03_N")), + Subsignal("miso", Pins("HPC:LA04_P")), + Subsignal("en", Pins("HPC:LA05_N")), + IOStandard("LVTTL"), + ), + ("ad9154_txen", 0, Pins("HPC:LA07_P"), IOStandard("LVTTL")), + ("ad9154_txen", 1, Pins("HPC:LA07_N"), IOStandard("LVTTL")), + ("ad9154_refclk", 0, + Subsignal("p", Pins("HPC:GBTCLK0_M2C_P")), + Subsignal("n", Pins("HPC:GBTCLK0_M2C_N")), + ), + ("ad9154_sysref", 0, + Subsignal("p", Pins("HPC:LA00_CC_P")), + Subsignal("n", Pins("HPC:LA00_CC_N")), + IOStandard("LVDS_25"), + ), + ("ad9154_sync", 0, + Subsignal("p", Pins("HPC:LA01_CC_P")), + Subsignal("n", Pins("HPC:LA01_CC_N")), + IOStandard("LVDS_25"), + ), + ("ad9154_sync", 1, + Subsignal("p", Pins("HPC:LA02_P")), + Subsignal("n", Pins("HPC:LA02_N")), + IOStandard("LVDS_25"), + ), + ("ad9154_jesd", 0, # AD9154's SERIND7 + Subsignal("txp", Pins("HPC:DP0_C2M_P")), + Subsignal("txn", Pins("HPC:DP0_C2M_N")) + ), + ("ad9154_jesd", 1, # AD9154's SERIND6 + Subsignal("txp", Pins("HPC:DP1_C2M_P")), + Subsignal("txn", Pins("HPC:DP1_C2M_N")) + ), + ("ad9154_jesd", 2, # AD9154's SERIND5 + Subsignal("txp", Pins("HPC:DP2_C2M_P")), + Subsignal("txn", Pins("HPC:DP2_C2M_N")) + ), + ("ad9154_jesd", 3, # AD9154's SERIND4 + Subsignal("txp", Pins("HPC:DP3_C2M_P")), + Subsignal("txn", Pins("HPC:DP3_C2M_N")) + ), + ("ad9154_jesd", 4, # AD9154's SERIND2 + Subsignal("txp", Pins("HPC:DP4_C2M_P")), + Subsignal("txn", Pins("HPC:DP4_C2M_N")) + ), + ("ad9154_jesd", 5, # AD9154's SERIND0 + Subsignal("txp", Pins("HPC:DP5_C2M_P")), + Subsignal("txn", Pins("HPC:DP5_C2M_N")) + ), + ("ad9154_jesd", 6, # AD9154's SERIND1 + Subsignal("txp", Pins("HPC:DP6_C2M_P")), + Subsignal("txn", Pins("HPC:DP6_C2M_N")) + ), + ("ad9154_jesd", 7, # AD9154's SERIND3 + Subsignal("txp", Pins("HPC:DP7_C2M_P")), + Subsignal("txn", Pins("HPC:DP7_C2M_N")) + ), +] diff --git a/artiq/gateware/rtio/phy/sawg.py b/artiq/gateware/rtio/phy/sawg.py new file mode 100644 index 000000000..fb520e968 --- /dev/null +++ b/artiq/gateware/rtio/phy/sawg.py @@ -0,0 +1,27 @@ +from collections import namedtuple + +from migen import * +from artiq.gateware.rtio import rtlink + +from artiq.gateware.dsp.sawg import DDSFast + + +_Phy = namedtuple("Phy", "rtlink probes overrides") + +DDSFast_rtio = ClockDomainsRenamer("rio_phy")(DDSFast) + + +class Channel(DDSFast_rtio): + def __init__(self, *args, **kwargs): + DDSFast_rtio.__init__(self, *args, **kwargs) + self.phys = [] + for i in self.i: + rl = rtlink.Interface(rtlink.OInterface(len(i.payload))) + self.comb += [ + i.stb.eq(rl.o.stb), + rl.o.busy.eq(~i.ack), + Cat(i.payload.flatten()).eq(rl.o.data), + ] + # no probes, overrides + self.phys.append(_Phy(rl, [], [])) + self.phys_names = dict(zip("afp", self.phys)) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 7209a2b3b..9bb439232 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -9,17 +9,20 @@ from migen.build.generic_platform import * from migen.build.xilinx.vivado import XilinxVivadoToolchain from migen.build.xilinx.ise import XilinxISEToolchain from migen.fhdl.specials import Keep +from migen.genlib.io import DifferentialInput from misoc.interconnect.csr import * from misoc.interconnect import wishbone from misoc.cores import gpio +from misoc.cores import spi as spi_csr from misoc.integration.soc_core import mem_decoder 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, nist_qc1, nist_clock, nist_qc2 -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi +from artiq.gateware import rtio, nist_qc1, nist_clock, nist_qc2, phaser +from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, + dds, spi, sawg) from artiq import __version__ as artiq_version @@ -138,8 +141,8 @@ class _NIST_Ions(MiniSoC, AMPSoC): self.register_kernel_cpu_csrdevice("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) + def add_rtio(self, rtio_channels, crg=_RTIOCRG): + self.submodules.rtio_crg = crg(self.platform, self.crg.cd_sys.clk) self.csr_devices.append("rtio_crg") self.submodules.rtio = rtio.RTIO(rtio_channels) self.register_kernel_cpu_csrdevice("rtio") @@ -380,6 +383,135 @@ class NIST_QC2(_NIST_Ions): self.config["DDS_RTIO_CLK_RATIO"] = 24 >> self.rtio.fine_ts_width +class _PhaserCRG(Module, AutoCSR): + def __init__(self, platform, rtio_internal_clk): + rtio_internal_clk = ClockSignal("sys4x") + + 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) + + refclk_pads = platform.request("ad9154_refclk") + platform.add_period_constraint(refclk_pads.p, 2.) + refclk = Signal() + 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=refclk), + Instance("BUFG", i_I=refclk, o_O=self.cd_refclk.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=2.0, p_CLKIN2_PERIOD=2.0, + i_CLKIN1=rtio_internal_clk, i_CLKIN2=self.cd_refclk.clk, + # Warning: CLKINSEL=0 means CLKIN2 is selected + i_CLKINSEL=~self._clock_sel.storage, + + # VCO @ 1GHz when using 500MHz input + p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=4, + 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 Phaser(_NIST_Ions): + mem_map = {"ad9154_spi": 0x18000000} + mem_map.update(_NIST_Ions.mem_map) + + def __init__(self, cpu_type="or1k", **kwargs): + _NIST_Ions.__init__(self, cpu_type, **kwargs) + + platform = self.platform + platform.add_extension(phaser.fmc_adapter_io) + + sysref_pads = platform.request("ad9154_sysref") + #sysref = Signal() + #self.specials += DifferentialInput( + # sysref_pads.p, sysref_pads.n, sysref) + sync_pads = platform.request("ad9154_sync") + #sync = Signal() + #self.specials += DifferentialInput( + # sync_pads.p, sync_pads.n, sync) + + #for i in range(4): + # jesd_pads = platform.request("ad9154_jesd", i) + + rtio_channels = [] + + 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=128)) + + phy = ttl_simple.Output(platform.request("user_led", 2)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + 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_serdes_7series.Input_8X(sync_pads.p, sync_pads.n) + 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) + + ad9154_spi = self.platform.request("ad9154_spi") + self.submodules.ad9154_spi = spi_csr.SPIMaster(ad9154_spi) + self.register_kernel_cpu_csrdevice("ad9154_spi") + self.config["AD9154_DAC_CS"] = 1 << 0 + self.config["AD9154_CLK_CS"] = 1 << 1 + self.comb += [ + ad9154_spi.en.eq(1), + self.platform.request("ad9154_txen", 0).eq(1), + self.platform.request("ad9154_txen", 1).eq(1), + ] + + self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) + sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] + self.submodules += sawgs + + # TODO: dummy, hookup jesd204b phy here + o = Signal((16, True)) + for ch in sawgs: # gather up dangling outputs + for oi in ch.o: + o0, o = o, Signal.like(o) + self.sync += o.eq(o0 + oi) + self.sync.rio_phy += platform.request("user_led").eq(o[-1]) + + rtio_channels.extend(rtio.Channel.from_phy(phy) + for sawg in sawgs + for phy in sawg.phys) + + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + self.add_rtio(rtio_channels, _PhaserCRG) + + def main(): parser = argparse.ArgumentParser( description="ARTIQ core device builder / KC705 " @@ -388,7 +520,7 @@ def main(): soc_kc705_args(parser) parser.add_argument("-H", "--hw-adapter", default="nist_clock", help="hardware adapter type: " - "nist_qc1/nist_clock/nist_qc2 " + "nist_qc1/nist_clock/nist_qc2/phaser " "(default: %(default)s)") args = parser.parse_args() @@ -399,6 +531,8 @@ def main(): cls = NIST_CLOCK elif hw_adapter == "nist_qc2": cls = NIST_QC2 + elif hw_adapter == "phaser": + cls = Phaser else: raise SystemExit("Invalid hardware adapter string (-H/--hw-adapter)") diff --git a/artiq/runtime/Makefile b/artiq/runtime/Makefile index e0c276a12..d1c5e55cb 100644 --- a/artiq/runtime/Makefile +++ b/artiq/runtime/Makefile @@ -7,7 +7,7 @@ OBJECTS := isr.o clock.o rtiocrg.o flash_storage.o mailbox.o \ session.o log.o analyzer.o moninj.o net_server.o bridge_ctl.o \ ksupport_data.o kloader.o test_mode.o main.o OBJECTS_KSUPPORT := ksupport.o artiq_personality.o mailbox.o \ - bridge.o rtio.o dds.o i2c.o + bridge.o rtio.o dds.o i2c.o ad9154.o CFLAGS += -I$(LIBALLOC_DIRECTORY) \ -I$(MISOC_DIRECTORY)/software/include/dyld \ diff --git a/artiq/runtime/ad9154.c b/artiq/runtime/ad9154.c new file mode 100644 index 000000000..c646b72be --- /dev/null +++ b/artiq/runtime/ad9154.c @@ -0,0 +1,57 @@ +#include + +#include +#include + +#include "artiq_personality.h" +#include "ad9154.h" + +#ifdef CONFIG_AD9154_DAC_CS + +void ad9154_init(void) +{ + ad9154_spi_offline_write(1); + ad9154_spi_cs_polarity_write(0); + ad9154_spi_clk_polarity_write(0); + ad9154_spi_clk_phase_write(0); + ad9154_spi_lsb_first_write(0); + ad9154_spi_half_duplex_write(0); + ad9154_spi_clk_div_write_write(11); + ad9154_spi_clk_div_read_write(11); + ad9154_spi_xfer_len_write_write(24); + ad9154_spi_xfer_len_read_write(0); + ad9154_spi_cs_write(CONFIG_AD9154_DAC_CS); + ad9154_spi_offline_write(0); +} + +#define AD9_READ (1 << 15) +#define AD9_XFER(w) ((w) << 13) + +void ad9154_write(uint16_t addr, uint8_t data) +{ + ad9154_spi_data_write_write( + ((AD9_XFER(0) | addr) << 16) | (data << 8)); + while (ad9154_spi_pending_read()); + while (ad9154_spi_active_read()); +} + +uint8_t ad9154_read(uint16_t addr) +{ + ad9154_write(AD9_READ | addr, 0); + return ad9154_spi_data_read_read(); +} + +void ad9516_write(uint16_t addr, uint8_t data) +{ + ad9154_spi_cs_write(CONFIG_AD9154_CLK_CS); + ad9154_write(addr, data); + ad9154_spi_cs_write(CONFIG_AD9154_DAC_CS); +} + +uint8_t ad9516_read(uint16_t addr) +{ + ad9516_write(AD9_READ | addr, 0); + return ad9154_spi_data_read_read(); +} + +#endif /* CONFIG_AD9154_DAC_CS */ diff --git a/artiq/runtime/ad9154.h b/artiq/runtime/ad9154.h new file mode 100644 index 000000000..3db7ea633 --- /dev/null +++ b/artiq/runtime/ad9154.h @@ -0,0 +1,14 @@ +#ifndef __AD9154_H +#define __AD9154_H + +#ifdef CONFIG_AD9154_DAC_CS + +void ad9154_init(void); +void ad9154_write(uint16_t addr, uint8_t data); +uint8_t ad9154_read(uint16_t addr); + +void ad9516_write(uint16_t addr, uint8_t data); +uint8_t ad9516_read(uint16_t addr); + +#endif +#endif diff --git a/artiq/runtime/ksupport.c b/artiq/runtime/ksupport.c index 60a8eb023..1c24e6f84 100644 --- a/artiq/runtime/ksupport.c +++ b/artiq/runtime/ksupport.c @@ -17,6 +17,7 @@ #include "rtio.h" #include "dds.h" #include "i2c.h" +#include "ad9154.h" double round(double x); double sqrt(double x); @@ -137,6 +138,14 @@ static const struct symbol runtime_exports[] = { {"cache_get", &cache_get}, {"cache_put", &cache_put}, +#ifdef CONFIG_AD9154_DAC_CS + {"ad9154_init", &ad9154_init}, + {"ad9154_write", &ad9154_write}, + {"ad9154_read", &ad9154_read}, + {"ad9516_write", &ad9516_write}, + {"ad9516_read", &ad9516_read}, +#endif + /* end */ {NULL, NULL} }; diff --git a/artiq/runtime/main.c b/artiq/runtime/main.c index 25fdc3b31..81d4dbb31 100644 --- a/artiq/runtime/main.c +++ b/artiq/runtime/main.c @@ -34,6 +34,7 @@ #include "session.h" #include "analyzer.h" #include "moninj.h" +#include "ad9154.h" u32_t sys_now(void) { diff --git a/artiq/test/gateware/__init__.py b/artiq/test/gateware/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/artiq/test/gateware/test_accu.py b/artiq/test/gateware/test_accu.py new file mode 100644 index 000000000..4bc7066fb --- /dev/null +++ b/artiq/test/gateware/test_accu.py @@ -0,0 +1,46 @@ +import numpy as np + +from migen import * +from migen.fhdl.verilog import convert + +from artiq.gateware.dsp.accu import Accu, PhasedAccu +from artiq.gateware.dsp.tools import xfer + + +def read(o, n): + p = [] + for i in range(n): + p.append((yield from [(yield pi) for pi in o.payload.flatten()])) + yield + return p + + +def _test_gen_accu(dut, o): + yield dut.o.ack.eq(1) + yield from xfer(dut, i=dict(p=0, f=1, clr=1)) + o.extend((yield from read(dut.o, 8))) + yield from xfer(dut, i=dict(p=0, f=2, clr=0)) + o.extend((yield from read(dut.o, 8))) + yield from xfer(dut, i=dict(p=0, f=2, clr=1)) + o.extend((yield from read(dut.o, 8))) + yield from xfer(dut, i=dict(p=8, f=-1, clr=1)) + o.extend((yield from read(dut.o, 8))) + yield from xfer(dut, i=dict(p=0, f=0, clr=1)) + yield from xfer(dut, i=dict(p=1, f=0, clr=0)) + o.extend((yield from read(dut.o, 8))) + + +def _test_accu(): + dut = PhasedAccu(8, parallelism=8) + + if False: + print(convert(dut)) + else: + o = [] + run_simulation(dut, _test_gen_accu(dut, o), vcd_name="accu.vcd") + o = np.array(o) + print(o) + + +if __name__ == "__main__": + _test_accu() diff --git a/artiq/test/gateware/test_sawg.py b/artiq/test/gateware/test_sawg.py new file mode 100644 index 000000000..4ffd4ba78 --- /dev/null +++ b/artiq/test/gateware/test_sawg.py @@ -0,0 +1,34 @@ +import numpy as np + +from migen import * +from migen.fhdl.verilog import convert + +from artiq.gateware.dsp.sawg import DDSFast +from artiq.gateware.dsp.tools import xfer + + +def _test_gen_dds(dut, o): + yield from xfer(dut, + a=dict(a=10), + p=dict(p=0), + f=dict(f=1 << 8), + ) + for i in range(256//dut.parallelism): + yield + o.append((yield from [(yield _) for _ in dut.o])) + + +def _test_channel(): + dut = DDSFast(width=8, parallelism=2) + + if False: + print(convert(dut)) + else: + o = [] + run_simulation(dut, _test_gen_dds(dut, o), vcd_name="dds.vcd") + o = np.array(o) + print(o[:, :]) + + +if __name__ == "__main__": + _test_channel() diff --git a/artiq/test/gateware/test_sawg_phy.py b/artiq/test/gateware/test_sawg_phy.py new file mode 100644 index 000000000..5b922968f --- /dev/null +++ b/artiq/test/gateware/test_sawg_phy.py @@ -0,0 +1,61 @@ +import numpy as np + +from migen import * +from migen.fhdl.verilog import convert + +from artiq.gateware.rtio.phy.sawg import Channel +from artiq.gateware.dsp.tools import xfer, szip + + +def rtio_xfer(dut, **kwargs): + yield from szip(*( + xfer(dut.phys_names[k].rtlink, o={"data": v}) + for k, v in kwargs.items())) + + +def gen_rtio(dut): + width = dut.width + yield + yield from rtio_xfer( + dut, a=int(.1 * (1 << width)), + f=int(.01234567 * (1 << 2*width)), + p=0) + + +def gen_log(dut, o, n): + for i in range(3 + dut.latency): + yield + for i in range(n): + yield + o.append((yield from [(yield _) for _ in dut.o])) + + +def _test_channel(): + width = 16 + dut = ClockDomainsRenamer({"rio_phy": "sys"})( + Channel(width=width, parallelism=4) + ) + + if False: + print(convert(dut)) + return + + o = [] + run_simulation( + dut, + [gen_rtio(dut), gen_log(dut, o, 256 * 2)], + ) # vcd_name="dds.vcd") + o = np.array(o)/(1 << (width - 1)) + o = o.ravel() + np.savez_compressed("dds.npz", o=o) + + import matplotlib.pyplot as plt + fig, ax = plt.subplots(2) + ax[0].step(np.arange(o.size), o) + ax[1].psd(o, 1 << 10, Fs=1, noverlap=1 << 9, scale_by_freq=False) + fig.savefig("dds.pdf") + plt.show() + + +if __name__ == "__main__": + _test_channel() diff --git a/conda/artiq-kc705-phaser/build.sh b/conda/artiq-kc705-phaser/build.sh new file mode 100644 index 000000000..78af5b75c --- /dev/null +++ b/conda/artiq-kc705-phaser/build.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +BUILD_SETTINGS_FILE=$HOME/.m-labs/build_settings.sh +[ -f $BUILD_SETTINGS_FILE ] && . $BUILD_SETTINGS_FILE + +SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kc705-phaser +mkdir -p $SOC_PREFIX + +$PYTHON -m artiq.gateware.targets.kc705 -H phaser --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE +cp misoc_phaser_kc705/gateware/top.bit $SOC_PREFIX +cp misoc_phaser_kc705/software/bios/bios.bin $SOC_PREFIX +cp misoc_phaser_kc705/software/runtime/runtime.fbi $SOC_PREFIX + +wget -P $SOC_PREFIX https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/master/bscan_spi_xc7k325t.bit diff --git a/conda/artiq-kc705-phaser/meta.yaml b/conda/artiq-kc705-phaser/meta.yaml new file mode 100644 index 000000000..6c24032ba --- /dev/null +++ b/conda/artiq-kc705-phaser/meta.yaml @@ -0,0 +1,27 @@ +package: + name: artiq-kc705-phaser + version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} + +source: + git_url: ../.. + +build: + noarch_python: true + number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} + string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_DESCRIBE_HASH", "")[1:] }} + +requirements: + build: + - migen 0.4 + - misoc 0.3 + - llvm-or1k + - binutils-or1k-linux >=2.27 + - rust-core-or1k + - cargo + run: + - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_DESCRIBE_HASH")[1:]) if "GIT_DESCRIBE_TAG" in environ else "" }} + +about: + home: https://m-labs.hk/artiq + license: GPL + summary: 'Bitstream, BIOS and runtime for Phaser on the KC705 board' diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index eae66caa2..695248ba6 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -155,6 +155,38 @@ To avoid I/O contention, the startup kernel should first program the TCA6424A ex See :mod:`artiq.coredevice.i2c` for more details. + +Phaser +++++++ + +The Phaser adapter is an AD9154-FMC-EBZ, a 4 channel 2.4 GHz DAC on an FMC HPC card. + ++--------------+------------+--------------+ +| RTIO channel | TTL line | Capability | ++==============+============+==============+ +| 0 | SMA_GPIO_N | Input+Output | ++--------------+------------+--------------+ +| 1 | LED | Output | ++--------------+------------+--------------+ +| 2 | SYSREF | Input | ++--------------+------------+--------------+ +| 3 | SYNC | Input | ++--------------+------------+--------------+ + +The SAWG channels start with RTIO channel number 4, each occupying 3 channels. + +The board has one non-RTIO SPI bus that is accessible through +:mod:`artiq.coredevice.ad9154`. + +* Setup the KC705 observing the notes above and as laid out in :ref:`configuring-core-device`. +* A 2 GHz of roughly 10 dBm (0.2 to 3.4 V peak-to-peak into 50 Ohm) must be connected to the AD9154-FMC-EBZ J1. + The external RTIO clock, DAC deviceclock, FPGA deviceclock, and SYSREF are derived from this signal. +* The ``startup_clock`` needs to be set to internal (``i``) for bootstrapping the clock distribution tree. + See :ref:`configuring-core-device`. +* Compile and flash the startup kernel in ``artiq/examples/phaser/startup_kernel.py``. +* An example ``device_db.pyon`` is provided in ``artiq/examples/phaser/device_db.pyon``. + + Pipistrello ----------- diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 9895b04f7..f6065de25 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -53,3 +53,15 @@ These drivers are for the core device and the peripherals closely integrated int .. automodule:: artiq.coredevice.exceptions :members: + +:mod:`artiq.coredevice.sawg` module +----------------------------------- + +.. automodule:: artiq.coredevice.sawg + :members: + +:mod:`artiq.coredevice.ad9154` module +----------------------------------- + +.. automodule:: artiq.coredevice.ad9154 + :members: diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index c3090337b..0b1ffc64d 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -142,6 +142,7 @@ Then, you can flash the board: For the KC705, the next step is to flash the MAC and IP addresses to the board. See :ref:`those instructions `. +.. _configuring-core-device: Configuring the core device --------------------------- From c54b6e2f3c63ba0d1153395c56fc0ba688968c36 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 5 Oct 2016 19:24:34 +0200 Subject: [PATCH 005/157] phaser: add README --- README_PHASER.rst | 104 +++++++++++++++++++++++++++++++++++++ doc/manual/core_device.rst | 8 --- 2 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 README_PHASER.rst diff --git a/README_PHASER.rst b/README_PHASER.rst new file mode 100644 index 000000000..a1a4fc653 --- /dev/null +++ b/README_PHASER.rst @@ -0,0 +1,104 @@ +ARTIQ Phaser +============ + +This ARTIQ branch contains a proof-of-concept design of a GHz-datarate multichannel direct digital synthesizer (DDS) compatible with ARTIQ's RTIO channels. +In later developments this proof-of-concept can be expanded to provide a two-tone output with spline modulation and multi-DAC synchronization. +Ultimately it will be the basis for the ARTIQ Sayma project. See https://github.com/m-labs/sayma and https://github.com/m-labs/artiq-hardware + +The hardware required is a KC705 with an AD9154-FMC-EBZ plugged into the HPC connector and a low-jitter 2 GHz reference clock. + +Features: + + * 4 channels + * 500 MHz data rate per channel (KC705 limitation) + * 4x interpolation to 2 GHz DAC sample rate + * Real-time control over amplitude, frequency, phase through ARTIQ RTIO + channels + * Full configurability of the AD9154 and AD9516 through SPI with ARTIQ kernel + support + * All SPI registers and register bits exposed as human readable names + * Parametrized JESD204B core (also capable of operation with eight lanes) + * The code can be reconfigured, e.g. to support 2 channels at 1 GHz datarate or to support 4 channels at 300 MHz data rate, no interpolation, and using mix mode to stress the second and third Nyquist zones (150-300 MHz and 300-450 MHz). + +This work was supported by the Army Research Lab. + +The additions and modifications to ARTIQ that were implemented for this project are: + + * In ARTIQ, the SAWG and Phaser code: https://github.com/m-labs/artiq/compare/phaser + * The CORDIC core has been reused from the PDQ2 gateware + https://github.com/m-labs/pdq2 + * The Migen/MiSoC JESD204B core: https://github.com/enjoy-digital/litejesd204b +: + +Installation +------------ + +These installation instructions are a short form of those in the ARTIQ manual. +Please refer to the manual for more details: +https://m-labs.hk/artiq/manual-release-2/index.html + +* Set up a new conda environment and activate it. +* Checkout the ARTIQ phaser branch:: + git clone -b phaser https://github.com/m-labs/artiq.git + +* Install the standard ARTIQ runtime/install dependencies. + See ``conda/artiq/meta.yaml`` for a list. + They are all packaged as conda packages in ``m-labs/main``. + +* Install the standard ARTIQ build dependencies. + They are all available as conda packages in m-labs/main at least for linux-64: + + - migen 0.4 + - misoc 0.3 + - llvm-or1k + - rust-core-or1k + - cargo + - binutils-or1k-linux >=2.27 + +* Vivado + +Follow the ARTIQ manual's chapter on installing. + + +Setup +----- + +* Setup the KC705 (VADJ, jumpers, etc.) observing the ARTIQ manual. +* On the AD9154-FMC-EBZ put jumpers: + + - on XP1, between pin 5 and 6 (will keep the PIC in reset) + - on JP3 (will force output enable on FXLA108) + +* Compile the ARTIQ Phaser bitstream, bios, and runtime (c.f. ARTIQ manual)::: + python -m artiq.gateware.targets.kc705 -H phaser --toolchain vivado + +* Run the following OpenOCD commands to flash the ARTIQ transmitter design::: + init + jtagspi_init 0 bscan_spi_xc7k325t.bit + jtagspi_program misoc_phaser_kc705/gateware/top.bin 0x000000 + jtagspi_program misoc_phaser_kc705/software/bios/bios.bin 0xaf0000 + jtagspi_program misoc_phaser_kc705/software/runtime/runtime.fbi 0xb00000 + xc7_program xc7.tap + exit + + The proxy bitstream ``bscan_spi_xc7k325t.bit`` can be found at https://github.com/jordens/bscan_spi_bitstreams or in any ARTIQ conda package for the KC705. See the source code of ``artiq_flash.py`` from ARTIQ for more details. + +* Refer to the ARTIQ documentation to configure an IP address and other settings for the transmitter device. + If the board was running stock ARTIQ before, the settings will be kept. +* A 2 GHz of roughly 10 dBm (0.2 to 3.4 V peak-to-peak into 50 Ohm) must be connected to the AD9154-FMC-EBZ J1. + The external RTIO clock, DAC deviceclock, FPGA deviceclock, and SYSREF are derived from this signal. +* The ``startup_clock`` needs to be set to internal (``i``) for bootstrapping the clock distribution tree. +* Compile and flash the startup kernel in ``artiq/examples/phaser/startup_kernel.py``. + +Usage +----- + +* An example device database, several status and test scripts are provided in ``artiq/examples/phaser/``. +* run ``artiq_run sawg.py`` for an example that sets up amplitudes, frequencies, + and phases on all four DDS channels. +* Implement your own experiments using the SAWG channels. +* Verify clock stability between the 2 GHz reference clock and the DAC outputs. +* Verify phase alignment between the DAC channels. +* Changes to the AD9154 configuration can also be performed at runtime in experiments. + See the example ``startup_kernel.py``. + This can e.g. be used to enable and evaluate mix mode without having to change any other code (bitstream/bios/runtime/startup_kernel). diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index 695248ba6..389e11fa4 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -178,14 +178,6 @@ The SAWG channels start with RTIO channel number 4, each occupying 3 channels. The board has one non-RTIO SPI bus that is accessible through :mod:`artiq.coredevice.ad9154`. -* Setup the KC705 observing the notes above and as laid out in :ref:`configuring-core-device`. -* A 2 GHz of roughly 10 dBm (0.2 to 3.4 V peak-to-peak into 50 Ohm) must be connected to the AD9154-FMC-EBZ J1. - The external RTIO clock, DAC deviceclock, FPGA deviceclock, and SYSREF are derived from this signal. -* The ``startup_clock`` needs to be set to internal (``i``) for bootstrapping the clock distribution tree. - See :ref:`configuring-core-device`. -* Compile and flash the startup kernel in ``artiq/examples/phaser/startup_kernel.py``. -* An example ``device_db.pyon`` is provided in ``artiq/examples/phaser/device_db.pyon``. - Pipistrello ----------- From d13f67cf63750d9371dab988a40f6c3856f8c744 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 5 Oct 2016 19:25:53 +0200 Subject: [PATCH 006/157] phaser: fix README --- README_PHASER.rst | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/README_PHASER.rst b/README_PHASER.rst index a1a4fc653..a2d1abf30 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -9,26 +9,26 @@ The hardware required is a KC705 with an AD9154-FMC-EBZ plugged into the HPC con Features: - * 4 channels - * 500 MHz data rate per channel (KC705 limitation) - * 4x interpolation to 2 GHz DAC sample rate - * Real-time control over amplitude, frequency, phase through ARTIQ RTIO - channels - * Full configurability of the AD9154 and AD9516 through SPI with ARTIQ kernel - support - * All SPI registers and register bits exposed as human readable names - * Parametrized JESD204B core (also capable of operation with eight lanes) - * The code can be reconfigured, e.g. to support 2 channels at 1 GHz datarate or to support 4 channels at 300 MHz data rate, no interpolation, and using mix mode to stress the second and third Nyquist zones (150-300 MHz and 300-450 MHz). +* 4 channels +* 500 MHz data rate per channel (KC705 limitation) +* 4x interpolation to 2 GHz DAC sample rate +* Real-time control over amplitude, frequency, phase through ARTIQ RTIO + channels +* Full configurability of the AD9154 and AD9516 through SPI with ARTIQ kernel + support +* All SPI registers and register bits exposed as human readable names +* Parametrized JESD204B core (also capable of operation with eight lanes) +* The code can be reconfigured, e.g. to support 2 channels at 1 GHz datarate or to support 4 channels at 300 MHz data rate, no interpolation, and using mix mode to stress the second and third Nyquist zones (150-300 MHz and 300-450 MHz). This work was supported by the Army Research Lab. The additions and modifications to ARTIQ that were implemented for this project are: - * In ARTIQ, the SAWG and Phaser code: https://github.com/m-labs/artiq/compare/phaser - * The CORDIC core has been reused from the PDQ2 gateware - https://github.com/m-labs/pdq2 - * The Migen/MiSoC JESD204B core: https://github.com/enjoy-digital/litejesd204b -: +* In ARTIQ, the SAWG and Phaser code: https://github.com/m-labs/artiq/compare/phaser +* The CORDIC core has been reused from the PDQ2 gateware + https://github.com/m-labs/pdq2 +* The Migen/MiSoC JESD204B core: https://github.com/enjoy-digital/litejesd204b + Installation ------------ @@ -38,7 +38,8 @@ Please refer to the manual for more details: https://m-labs.hk/artiq/manual-release-2/index.html * Set up a new conda environment and activate it. -* Checkout the ARTIQ phaser branch:: +* Checkout the ARTIQ phaser branch: :: + git clone -b phaser https://github.com/m-labs/artiq.git * Install the standard ARTIQ runtime/install dependencies. @@ -69,10 +70,12 @@ Setup - on XP1, between pin 5 and 6 (will keep the PIC in reset) - on JP3 (will force output enable on FXLA108) -* Compile the ARTIQ Phaser bitstream, bios, and runtime (c.f. ARTIQ manual)::: +* Compile the ARTIQ Phaser bitstream, bios, and runtime (c.f. ARTIQ manual): :: + python -m artiq.gateware.targets.kc705 -H phaser --toolchain vivado -* Run the following OpenOCD commands to flash the ARTIQ transmitter design::: +* Run the following OpenOCD commands to flash the ARTIQ transmitter design: :: + init jtagspi_init 0 bscan_spi_xc7k325t.bit jtagspi_program misoc_phaser_kc705/gateware/top.bin 0x000000 From f62d60093e5542589d48936b1444eae6e7cddca2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 6 Oct 2016 09:58:05 +0200 Subject: [PATCH 007/157] README_PHASER: update --- README_PHASER.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README_PHASER.rst b/README_PHASER.rst index a2d1abf30..780d17320 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -27,7 +27,7 @@ The additions and modifications to ARTIQ that were implemented for this project * In ARTIQ, the SAWG and Phaser code: https://github.com/m-labs/artiq/compare/phaser * The CORDIC core has been reused from the PDQ2 gateware https://github.com/m-labs/pdq2 -* The Migen/MiSoC JESD204B core: https://github.com/enjoy-digital/litejesd204b +* The Migen/MiSoC JESD204B core: https://github.com/m-labs/jesd204 Installation @@ -40,7 +40,7 @@ https://m-labs.hk/artiq/manual-release-2/index.html * Set up a new conda environment and activate it. * Checkout the ARTIQ phaser branch: :: - git clone -b phaser https://github.com/m-labs/artiq.git + git clone --recursive -b phaser https://github.com/m-labs/artiq.git * Install the standard ARTIQ runtime/install dependencies. See ``conda/artiq/meta.yaml`` for a list. From 4d87f0e9e076c8739580214bd7e0f62af251286a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 6 Oct 2016 12:00:01 +0200 Subject: [PATCH 008/157] phaser: instantiate jesd204b core, wire up --- README_PHASER.rst | 2 +- artiq/coredevice/ad9154.py | 29 ++++++++ artiq/examples/phaser/device_db.pyon | 14 +--- artiq/examples/phaser/startup_kernel.py | 98 +++++++++++++++---------- artiq/gateware/targets/kc705.py | 79 +++++++++++++------- artiq/runtime/ad9154.c | 15 ++++ artiq/runtime/ad9154.h | 4 + artiq/runtime/ksupport.c | 3 + doc/manual/core_device.rst | 4 +- 9 files changed, 167 insertions(+), 81 deletions(-) diff --git a/README_PHASER.rst b/README_PHASER.rst index 780d17320..9bd637b86 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -27,7 +27,7 @@ The additions and modifications to ARTIQ that were implemented for this project * In ARTIQ, the SAWG and Phaser code: https://github.com/m-labs/artiq/compare/phaser * The CORDIC core has been reused from the PDQ2 gateware https://github.com/m-labs/pdq2 -* The Migen/MiSoC JESD204B core: https://github.com/m-labs/jesd204 +* The Migen/MiSoC JESD204B core: https://github.com/m-labs/jesd204b Installation diff --git a/artiq/coredevice/ad9154.py b/artiq/coredevice/ad9154.py index d13fb4a2e..09612f944 100644 --- a/artiq/coredevice/ad9154.py +++ b/artiq/coredevice/ad9154.py @@ -27,6 +27,21 @@ def ad9516_read(addr: TInt32) -> TInt32: raise NotImplementedError("syscall not simulated") +@syscall(flags={"nounwind", "nowrite"}) +def jesd_enable(en: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + + +@syscall(flags={"nounwind", "nowrite"}) +def jesd_ready() -> TInt32: + raise NotImplementedError("syscall not simulated") + + +@syscall(flags={"nounwind", "nowrite"}) +def jesd_prbs(prbs: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + + class AD9154: """AD9154-FMC-EBZ SPI support @@ -66,3 +81,17 @@ class AD9154: def clock_read(self, addr): """Read AD9516 SPI register at `addr`.""" return ad9516_read(addr) + + @kernel + def jesd_enable(self, en): + """Enables the JESD204B core startup sequence.""" + jesd_enable(en) + + @kernel + def jesd_ready(self): + """Returns `True` if the JESD links are up.""" + return jesd_ready() + + @kernel + def jesd_prbs(self, prbs): + jesd_prbs(prbs) diff --git a/artiq/examples/phaser/device_db.pyon b/artiq/examples/phaser/device_db.pyon index c9bfe06f5..f1b441921 100644 --- a/artiq/examples/phaser/device_db.pyon +++ b/artiq/examples/phaser/device_db.pyon @@ -44,34 +44,28 @@ "class": "TTLInOut", "arguments": {"channel": 2} }, - "sync": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut", - "arguments": {"channel": 3} - }, "sawg0": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 4, "parallelism": 4} + "arguments": {"channel_base": 3, "parallelism": 4} }, "sawg1": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 7, "parallelism": 4} + "arguments": {"channel_base": 6, "parallelism": 4} }, "sawg2": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 10, "parallelism": 4} + "arguments": {"channel_base": 9, "parallelism": 4} }, "sawg3": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 13, "parallelism": 4} + "arguments": {"channel_base": 12, "parallelism": 4} } } diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index 76c8a6816..5b1821b17 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -1,7 +1,33 @@ +from jesd204b.common import (JESD204BPhysicalSettings, + JESD204BTransportSettings, + JESD204BSettings) from artiq.experiment import * from artiq.coredevice.ad9516_reg import * from artiq.coredevice.ad9154_reg import * +# ad9154 mode 2: +ps = JESD204BPhysicalSettings( + l=4, # lanes + m=4, # converters + n=16, # bits/converter + np=16, # bits/sample + sc=250*1e6, # data clock, unused: FIXME +) +ts = JESD204BTransportSettings( + f=2, # octets/(lane and frame) + s=1, # samples/(converter and frame) + k=16, # frames/multiframe + cs=1, # +) +jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) +jesd_checksum = jesd_settings.get_configuration_data()[-1] +jesd_data_freq = 250e6 +jesd_linerate = 5e9 +# external clk=2000MHz +# pclock=250MHz +# deviceclock_fpga=500MHz +# deviceclock_dac=2000MHz + class StartupKernel(EnvExperiment): def build(self): @@ -11,26 +37,16 @@ class StartupKernel(EnvExperiment): @kernel def run(self): - # ad9154 mode 2: - # M=4 converters - # L=4 lanes - # S=1 samples/converter and /frame - # F=2 octets/lane and /frame - # K=16 frames/multiframe (or 32) - # HD=0 high density - # N=16 bits/converter - # NB=16 bits/sample - # - # external clk=2000MHz - # pclock=250MHz - # fdata=500MHz - # fline=10GHz - # deviceclock_fpga=500MHz - # deviceclock_dac=2000MHz self.core.reset() + self.ad9154.jesd_enable(0) self.ad9154.init() self.clock_setup() self.dac_setup() + self.ad9154.jesd_prbs(0) + t = now_mu() + seconds_to_mu(.1*s) + while self.core.get_rtio_counter_mu() < t: + pass + self.ad9154.jesd_enable(1) @kernel def clock_setup(self): @@ -123,7 +139,7 @@ class StartupKernel(EnvExperiment): self.ad9154.dac_write(AD9154_SPI_PAGEINDX, 0x3) # A and B dual - self.ad9154.dac_write(AD9154_INTERP_MODE, 3) # 4x + self.ad9154.dac_write(AD9154_INTERP_MODE, 4) # 8x 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_DATAPATH_CTRL, @@ -160,24 +176,28 @@ class StartupKernel(EnvExperiment): self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_0, AD9154_LINK_EN_SET(0x0) | AD9154_LINK_PAGE_SET(0) | AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0)) - self.ad9154.dac_write(AD9154_ILS_DID, 0x00) # device id - self.ad9154.dac_write(AD9154_ILS_BID, 0x00) # band id + self.ad9154.dac_write(AD9154_ILS_DID, jesd_settings.did) + self.ad9154.dac_write(AD9154_ILS_BID, jesd_settings.bid) self.ad9154.dac_write(AD9154_ILS_LID0, 0x00) # lane id - self.ad9154.dac_write(AD9154_ILS_SCR_L, AD9154_L_1_SET(4 - 1) | AD9154_SCR_SET(1)) - self.ad9154.dac_write(AD9154_ILS_F, 2 - 1) - self.ad9154.dac_write(AD9154_ILS_K, 16 - 1) - self.ad9154.dac_write(AD9154_ILS_M, 4 - 1) - self.ad9154.dac_write(AD9154_ILS_CS_N, AD9154_N_1_SET(16 - 1) | AD9154_CS_SET(0)) - self.ad9154.dac_write(AD9154_ILS_NP, AD9154_NP_1_SET(16 - 1) | - AD9154_SUBCLASSV_SET(1)) - self.ad9154.dac_write(AD9154_ILS_S, AD9154_S_1_SET(1 - 1) | AD9154_JESDV_SET(1)) - self.ad9154.dac_write(AD9154_ILS_HD_CF, AD9154_HD_SET(0) | AD9154_CF_SET(0)) - self.ad9154.dac_write(AD9154_ILS_CHECKSUM, - 0x00 + 0x00 + 0x00 + 1 + (4 - 1) + # DID BID LID SCR L - (2 - 1) + (16 - 1) + (4 - 1) + (16 - 1) + # F K M N - 1 + (16 - 1) + 1 + (1 - 1) + 0 # SUBC NP JESDV S HD - ) - self.ad9154.dac_write(AD9154_LANEDESKEW, 0xf0) + self.ad9154.dac_write(AD9154_ILS_SCR_L, + AD9154_L_1_SET(jesd_settings.phy.l - 1) | + AD9154_SCR_SET(1)) + self.ad9154.dac_write(AD9154_ILS_F, jesd_settings.transport.f - 1) + self.ad9154.dac_write(AD9154_ILS_K, jesd_settings.transport.k - 1) + self.ad9154.dac_write(AD9154_ILS_M, jesd_settings.phy.m - 1) + self.ad9154.dac_write(AD9154_ILS_CS_N, + AD9154_N_1_SET(jesd_settings.phy.n - 1) | + AD9154_CS_SET(0)) + self.ad9154.dac_write(AD9154_ILS_NP, + AD9154_NP_1_SET(jesd_settings.phy.np - 1) | + AD9154_SUBCLASSV_SET(jesd_settings.phy.subclassv)) + self.ad9154.dac_write(AD9154_ILS_S, + AD9154_S_1_SET(jesd_settings.transport.s - 1) | + AD9154_JESDV_SET(jesd_settings.phy.jesdv)) + self.ad9154.dac_write(AD9154_ILS_HD_CF, + AD9154_HD_SET(0) | AD9154_CF_SET(0)) + self.ad9154.dac_write(AD9154_ILS_CHECKSUM, jesd_checksum) + self.ad9154.dac_write(AD9154_LANEDESKEW, 0x0f) for i in range(8): self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_DIS_SET(0) | AD9154_DISABLE_ERR_CNTR_DIS_SET(0) | @@ -197,22 +217,22 @@ class StartupKernel(EnvExperiment): self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_UCC_SET(0) | AD9154_DISABLE_ERR_CNTR_UCC_SET(0) | AD9154_RST_ERR_CNTR_UCC_SET(0) | AD9154_LANE_ADDR_UCC_SET(i)) - self.ad9154.dac_write(AD9154_CTRLREG1, 2) # F + self.ad9154.dac_write(AD9154_CTRLREG1, jesd_settings.transport.f) self.ad9154.dac_write(AD9154_CTRLREG2, AD9154_ILAS_MODE_SET(0) | AD9154_THRESHOLD_MASK_EN_SET(0)) - self.ad9154.dac_write(AD9154_KVAL, 1) # 4*K multiframes during ILAS - self.ad9154.dac_write(AD9154_LANEENABLE, 0xf0) + self.ad9154.dac_write(AD9154_KVAL, 1) # *4*K multiframes during ILAS + self.ad9154.dac_write(AD9154_LANEENABLE, 0x0f) self.ad9154.dac_write(AD9154_TERM_BLK1_CTRLREG0, 1) self.ad9154.dac_write(AD9154_TERM_BLK2_CTRLREG0, 1) self.ad9154.dac_write(AD9154_SERDES_SPI_REG, 1) self.ad9154.dac_write(AD9154_CDR_OPERATING_MODE_REG_0, AD9154_CDR_OVERSAMP_SET(0) | AD9154_CDR_RESERVED_SET(0x2) | - AD9154_ENHALFRATE_SET(1)) + AD9154_ENHALFRATE_SET(0)) self.ad9154.dac_write(AD9154_CDR_RESET, 0) self.ad9154.dac_write(AD9154_CDR_RESET, 1) self.ad9154.dac_write(AD9154_REF_CLK_DIVIDER_LDO, - AD9154_SPI_CDR_OVERSAMP_SET(0x0) | + AD9154_SPI_CDR_OVERSAMP_SET(0x1) | AD9154_SPI_LDO_BYPASS_FILT_SET(1) | AD9154_SPI_LDO_REF_SEL_SET(0)) self.ad9154.dac_write(AD9154_LDO_FILTER_1, 0x62) # magic diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 9bb439232..2ca5ba001 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -11,6 +11,13 @@ from migen.build.xilinx.ise import XilinxISEToolchain from migen.fhdl.specials import Keep from migen.genlib.io import DifferentialInput +from jesd204b.common import (JESD204BTransportSettings, + JESD204BPhysicalSettings, + JESD204BSettings) +from jesd204b.phy import JESD204BPhyTX +from jesd204b.core import JESD204BCoreTX +from jesd204b.core import JESD204BCoreTXControl + from misoc.interconnect.csr import * from misoc.interconnect import wishbone from misoc.cores import gpio @@ -395,13 +402,12 @@ class _PhaserCRG(Module, AutoCSR): refclk_pads = platform.request("ad9154_refclk") platform.add_period_constraint(refclk_pads.p, 2.) - refclk = Signal() - refclk = Signal() + 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=refclk), - Instance("BUFG", i_I=refclk, o_O=self.cd_refclk.clk), + 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() @@ -436,7 +442,10 @@ class _PhaserCRG(Module, AutoCSR): class Phaser(_NIST_Ions): - mem_map = {"ad9154_spi": 0x18000000} + mem_map = { + "ad9154_spi": 0x50000000, + "jesd_control": 0x40000000, + } mem_map.update(_NIST_Ions.mem_map) def __init__(self, cpu_type="or1k", **kwargs): @@ -446,16 +455,6 @@ class Phaser(_NIST_Ions): platform.add_extension(phaser.fmc_adapter_io) sysref_pads = platform.request("ad9154_sysref") - #sysref = Signal() - #self.specials += DifferentialInput( - # sysref_pads.p, sysref_pads.n, sysref) - sync_pads = platform.request("ad9154_sync") - #sync = Signal() - #self.specials += DifferentialInput( - # sync_pads.p, sync_pads.n, sync) - - #for i in range(4): - # jesd_pads = platform.request("ad9154_jesd", i) rtio_channels = [] @@ -473,11 +472,6 @@ class Phaser(_NIST_Ions): rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32, ofifo_depth=2)) - phy = ttl_serdes_7series.Input_8X(sync_pads.p, sync_pads.n) - 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) ad9154_spi = self.platform.request("ad9154_spi") @@ -495,14 +489,6 @@ class Phaser(_NIST_Ions): sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] self.submodules += sawgs - # TODO: dummy, hookup jesd204b phy here - o = Signal((16, True)) - for ch in sawgs: # gather up dangling outputs - for oi in ch.o: - o0, o = o, Signal.like(o) - self.sync += o.eq(o0 + oi) - self.sync.rio_phy += platform.request("user_led").eq(o[-1]) - rtio_channels.extend(rtio.Channel.from_phy(phy) for sawg in sawgs for phy in sawg.phys) @@ -511,6 +497,43 @@ class Phaser(_NIST_Ions): rtio_channels.append(rtio.LogChannel()) self.add_rtio(rtio_channels, _PhaserCRG) + # jesd_sysref = Signal() + # self.specials += DifferentialInput( + # sysref_pads.p, sysref_pads.n, jesd_sysref) + sync_pads = platform.request("ad9154_sync") + jesd_sync = Signal() + self.specials += DifferentialInput( + sync_pads.p, sync_pads.n, jesd_sync) + + ps = JESD204BPhysicalSettings(l=4, m=4, n=16, np=16, sc=250*1e6) + ts = JESD204BTransportSettings(f=2, s=1, k=16, cs=1) + jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) + jesd_linerate = 5e9 + jesd_refclk_freq = 500e6 + rtio_freq = 125*1000*1000 + jesd_phys = [JESD204BPhyTX( + self.rtio_crg.refclk, jesd_refclk_freq, + platform.request("ad9154_jesd", i), + jesd_linerate, rtio_freq, i) for i in range(4)] + self.submodules += jesd_phys + for jesd_phy in jesd_phys: + platform.add_period_constraint( + jesd_phy.gtx.cd_tx.clk, + 40/jesd_linerate*1e9) + self.platform.add_false_path_constraints( + self.rtio_crg.cd_rtio.clk, + jesd_phy.gtx.cd_tx.clk) + self.submodules.jesd_core = JESD204BCoreTX( + jesd_phys, jesd_settings, converter_data_width=32) + self.comb += self.jesd_core.start.eq(jesd_sync) + self.submodules.jesd_control = JESD204BCoreTXControl(self.jesd_core) + self.register_kernel_cpu_csrdevice("jesd_control") + for i, ch in enumerate(sawgs): + conv = getattr(self.jesd_core.transport.sink, + "converter{}".format(i)) + # while at 5 GBps, take every second sample... FIXME + self.comb += conv.eq(Cat(ch.o[::2])) + def main(): parser = argparse.ArgumentParser( diff --git a/artiq/runtime/ad9154.c b/artiq/runtime/ad9154.c index c646b72be..83a00a614 100644 --- a/artiq/runtime/ad9154.c +++ b/artiq/runtime/ad9154.c @@ -54,4 +54,19 @@ uint8_t ad9516_read(uint16_t addr) return ad9154_spi_data_read_read(); } +void jesd_enable(int en) +{ + jesd_control_enable_write(en); +} + +int jesd_ready(void) +{ + return jesd_control_ready_read(); +} + +void jesd_prbs(int p) +{ + jesd_control_prbs_config_write(p); +} + #endif /* CONFIG_AD9154_DAC_CS */ diff --git a/artiq/runtime/ad9154.h b/artiq/runtime/ad9154.h index 3db7ea633..66041c89a 100644 --- a/artiq/runtime/ad9154.h +++ b/artiq/runtime/ad9154.h @@ -10,5 +10,9 @@ uint8_t ad9154_read(uint16_t addr); void ad9516_write(uint16_t addr, uint8_t data); uint8_t ad9516_read(uint16_t addr); +void jesd_enable(int en); +int jesd_ready(void); +void jesd_prbs(int p); + #endif #endif diff --git a/artiq/runtime/ksupport.c b/artiq/runtime/ksupport.c index 1c24e6f84..acd6df595 100644 --- a/artiq/runtime/ksupport.c +++ b/artiq/runtime/ksupport.c @@ -144,6 +144,9 @@ static const struct symbol runtime_exports[] = { {"ad9154_read", &ad9154_read}, {"ad9516_write", &ad9516_write}, {"ad9516_read", &ad9516_read}, + {"jesd_enable", &jesd_enable}, + {"jesd_ready", &jesd_ready}, + {"jesd_prbs", &jesd_prbs}, #endif /* end */ diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index 389e11fa4..7f48d719a 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -170,10 +170,8 @@ The Phaser adapter is an AD9154-FMC-EBZ, a 4 channel 2.4 GHz DAC on an FMC HPC c +--------------+------------+--------------+ | 2 | SYSREF | Input | +--------------+------------+--------------+ -| 3 | SYNC | Input | -+--------------+------------+--------------+ -The SAWG channels start with RTIO channel number 4, each occupying 3 channels. +The SAWG channels start with RTIO channel number 3, each occupying 3 channels. The board has one non-RTIO SPI bus that is accessible through :mod:`artiq.coredevice.ad9154`. From 1193ba4bf418b5c6c66d3ff4d98361be3de5a463 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 6 Oct 2016 15:32:06 +0200 Subject: [PATCH 009/157] ad9154: merge csr spaces --- artiq/coredevice/ad9154.py | 12 ++-- artiq/examples/phaser/startup_kernel.py | 3 - artiq/gateware/targets/kc705.py | 88 +++++++++++++------------ artiq/runtime/ad9154.c | 12 ++-- artiq/runtime/ad9154.h | 6 +- artiq/runtime/ksupport.c | 6 +- 6 files changed, 64 insertions(+), 63 deletions(-) diff --git a/artiq/coredevice/ad9154.py b/artiq/coredevice/ad9154.py index 09612f944..792c56652 100644 --- a/artiq/coredevice/ad9154.py +++ b/artiq/coredevice/ad9154.py @@ -28,17 +28,17 @@ def ad9516_read(addr: TInt32) -> TInt32: @syscall(flags={"nounwind", "nowrite"}) -def jesd_enable(en: TInt32) -> TNone: +def ad9154_jesd_enable(en: TInt32) -> TNone: raise NotImplementedError("syscall not simulated") @syscall(flags={"nounwind", "nowrite"}) -def jesd_ready() -> TInt32: +def ad9154_jesd_ready() -> TInt32: raise NotImplementedError("syscall not simulated") @syscall(flags={"nounwind", "nowrite"}) -def jesd_prbs(prbs: TInt32) -> TNone: +def ad9154_jesd_prbs(prbs: TInt32) -> TNone: raise NotImplementedError("syscall not simulated") @@ -85,13 +85,13 @@ class AD9154: @kernel def jesd_enable(self, en): """Enables the JESD204B core startup sequence.""" - jesd_enable(en) + ad9154_jesd_enable(en) @kernel def jesd_ready(self): """Returns `True` if the JESD links are up.""" - return jesd_ready() + return ad9154_jesd_ready() @kernel def jesd_prbs(self, prbs): - jesd_prbs(prbs) + ad9154_jesd_prbs(prbs) diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index 5b1821b17..7ef671fab 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -11,7 +11,6 @@ ps = JESD204BPhysicalSettings( m=4, # converters n=16, # bits/converter np=16, # bits/sample - sc=250*1e6, # data clock, unused: FIXME ) ts = JESD204BTransportSettings( f=2, # octets/(lane and frame) @@ -21,8 +20,6 @@ ts = JESD204BTransportSettings( ) jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) jesd_checksum = jesd_settings.get_configuration_data()[-1] -jesd_data_freq = 250e6 -jesd_linerate = 5e9 # external clk=2000MHz # pclock=250MHz # deviceclock_fpga=500MHz diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 2ca5ba001..d517756cc 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -441,10 +441,48 @@ class _PhaserCRG(Module, AutoCSR): ] +class AD9154(Module, AutoCSR): + def __init__(self, platform, rtio_crg): + 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) + + ps = JESD204BPhysicalSettings(l=4, m=4, n=16, np=16) + ts = JESD204BTransportSettings(f=2, s=1, k=16, cs=1) + jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) + jesd_linerate = 5e9 + jesd_refclk_freq = 500e6 + rtio_freq = 125*1000*1000 + jesd_phys = [JESD204BPhyTX( + rtio_crg.refclk, jesd_refclk_freq, + platform.request("ad9154_jesd", i), + jesd_linerate, rtio_freq, i) for i in range(4)] + self.submodules += jesd_phys + for jesd_phy in jesd_phys: + platform.add_period_constraint( + jesd_phy.gtx.cd_tx.clk, + 40/jesd_linerate*1e9) + platform.add_false_path_constraints( + rtio_crg.cd_rtio.clk, + jesd_phy.gtx.cd_tx.clk) + self.submodules.jesd_core = JESD204BCoreTX( + jesd_phys, jesd_settings, converter_data_width=32) + self.comb += self.jesd_core.start.eq(jesd_sync) + self.submodules.jesd_control = JESD204BCoreTXControl(self.jesd_core) + + class Phaser(_NIST_Ions): mem_map = { - "ad9154_spi": 0x50000000, - "jesd_control": 0x40000000, + "ad9154": 0x50000000, } mem_map.update(_NIST_Ions.mem_map) @@ -474,17 +512,6 @@ class Phaser(_NIST_Ions): self.config["RTIO_REGULAR_TTL_COUNT"] = len(rtio_channels) - ad9154_spi = self.platform.request("ad9154_spi") - self.submodules.ad9154_spi = spi_csr.SPIMaster(ad9154_spi) - self.register_kernel_cpu_csrdevice("ad9154_spi") - self.config["AD9154_DAC_CS"] = 1 << 0 - self.config["AD9154_CLK_CS"] = 1 << 1 - self.comb += [ - ad9154_spi.en.eq(1), - self.platform.request("ad9154_txen", 0).eq(1), - self.platform.request("ad9154_txen", 1).eq(1), - ] - self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] self.submodules += sawgs @@ -500,36 +527,13 @@ class Phaser(_NIST_Ions): # jesd_sysref = Signal() # self.specials += DifferentialInput( # sysref_pads.p, sysref_pads.n, jesd_sysref) - sync_pads = platform.request("ad9154_sync") - jesd_sync = Signal() - self.specials += DifferentialInput( - sync_pads.p, sync_pads.n, jesd_sync) - - ps = JESD204BPhysicalSettings(l=4, m=4, n=16, np=16, sc=250*1e6) - ts = JESD204BTransportSettings(f=2, s=1, k=16, cs=1) - jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) - jesd_linerate = 5e9 - jesd_refclk_freq = 500e6 - rtio_freq = 125*1000*1000 - jesd_phys = [JESD204BPhyTX( - self.rtio_crg.refclk, jesd_refclk_freq, - platform.request("ad9154_jesd", i), - jesd_linerate, rtio_freq, i) for i in range(4)] - self.submodules += jesd_phys - for jesd_phy in jesd_phys: - platform.add_period_constraint( - jesd_phy.gtx.cd_tx.clk, - 40/jesd_linerate*1e9) - self.platform.add_false_path_constraints( - self.rtio_crg.cd_rtio.clk, - jesd_phy.gtx.cd_tx.clk) - self.submodules.jesd_core = JESD204BCoreTX( - jesd_phys, jesd_settings, converter_data_width=32) - self.comb += self.jesd_core.start.eq(jesd_sync) - self.submodules.jesd_control = JESD204BCoreTXControl(self.jesd_core) - self.register_kernel_cpu_csrdevice("jesd_control") + to_rtio = ClockDomainsRenamer({"sys": "rtio"}) + 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.jesd_core.transport.sink, + conv = getattr(self.ad9154.jesd_core.transport.sink, "converter{}".format(i)) # while at 5 GBps, take every second sample... FIXME self.comb += conv.eq(Cat(ch.o[::2])) diff --git a/artiq/runtime/ad9154.c b/artiq/runtime/ad9154.c index 83a00a614..0711af8dc 100644 --- a/artiq/runtime/ad9154.c +++ b/artiq/runtime/ad9154.c @@ -54,19 +54,19 @@ uint8_t ad9516_read(uint16_t addr) return ad9154_spi_data_read_read(); } -void jesd_enable(int en) +void ad9154_jesd_enable(int en) { - jesd_control_enable_write(en); + ad9154_jesd_control_enable_write(en); } -int jesd_ready(void) +int ad9154_jesd_ready(void) { - return jesd_control_ready_read(); + return ad9154_jesd_control_ready_read(); } -void jesd_prbs(int p) +void ad9154_jesd_prbs(int p) { - jesd_control_prbs_config_write(p); + ad9154_jesd_control_prbs_config_write(p); } #endif /* CONFIG_AD9154_DAC_CS */ diff --git a/artiq/runtime/ad9154.h b/artiq/runtime/ad9154.h index 66041c89a..9ea6d0e5d 100644 --- a/artiq/runtime/ad9154.h +++ b/artiq/runtime/ad9154.h @@ -10,9 +10,9 @@ uint8_t ad9154_read(uint16_t addr); void ad9516_write(uint16_t addr, uint8_t data); uint8_t ad9516_read(uint16_t addr); -void jesd_enable(int en); -int jesd_ready(void); -void jesd_prbs(int p); +void ad9154_jesd_enable(int en); +int ad9154_jesd_ready(void); +void ad9154_jesd_prbs(int p); #endif #endif diff --git a/artiq/runtime/ksupport.c b/artiq/runtime/ksupport.c index acd6df595..fb3f6dff5 100644 --- a/artiq/runtime/ksupport.c +++ b/artiq/runtime/ksupport.c @@ -144,9 +144,9 @@ static const struct symbol runtime_exports[] = { {"ad9154_read", &ad9154_read}, {"ad9516_write", &ad9516_write}, {"ad9516_read", &ad9516_read}, - {"jesd_enable", &jesd_enable}, - {"jesd_ready", &jesd_ready}, - {"jesd_prbs", &jesd_prbs}, + {"ad9154_jesd_enable", &ad9154_jesd_enable}, + {"ad9154_jesd_ready", &ad9154_jesd_ready}, + {"ad9154_jesd_prbs", &ad9154_jesd_prbs}, #endif /* end */ From fee78315734da4fe8706f1120603e7573a951827 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 6 Oct 2016 16:48:03 +0200 Subject: [PATCH 010/157] phaser: split setup --- artiq/examples/phaser/repository/dac_setup.py | 264 ++++++++++++++++++ artiq/examples/phaser/startup_kernel.py | 250 ----------------- 2 files changed, 264 insertions(+), 250 deletions(-) create mode 100644 artiq/examples/phaser/repository/dac_setup.py diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py new file mode 100644 index 000000000..50639d982 --- /dev/null +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -0,0 +1,264 @@ +from jesd204b.common import (JESD204BPhysicalSettings, + JESD204BTransportSettings, + JESD204BSettings) +from artiq.experiment import * +from artiq.coredevice.ad9154_reg import * + +# ad9154 mode 2: +ps = JESD204BPhysicalSettings( + l=4, # lanes + m=4, # converters + n=16, # bits/converter + np=16, # bits/sample +) +ts = JESD204BTransportSettings( + f=2, # octets/(lane and frame) + s=1, # samples/(converter and frame) + k=16, # frames/multiframe + cs=1, # +) +jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) +jesd_checksum = jesd_settings.get_configuration_data()[-1] +# external clk=2000MHz +# pclock=250MHz +# deviceclock_fpga=500MHz +# deviceclock_dac=2000MHz + + +class DACSetup(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("led") + self.setattr_device("ad9154") + + @kernel + def run(self): + self.core.reset() + self.ad9154.jesd_enable(0) + self.ad9154.init() + self.dac_setup() + self.ad9154.jesd_prbs(0) + t = now_mu() + seconds_to_mu(.1*s) + while self.core.get_rtio_counter_mu() < t: + pass + self.ad9154.jesd_enable(1) + + @kernel + def dac_setup(self): + # reset + self.ad9154.dac_write(AD9154_SPI_INTFCONFA, AD9154_SOFTRESET_SET(1) | + AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1)) + self.ad9154.dac_write(AD9154_SPI_INTFCONFA, + AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1)) + if ((self.ad9154.dac_read(AD9154_PRODIDH) << 8) | + self.ad9154.dac_read(AD9154_PRODIDL) != 0x9154): + return + + self.ad9154.dac_write(AD9154_PWRCNTRL0, + AD9154_PD_DAC0_SET(0) | AD9154_PD_DAC1_SET(0) | + AD9154_PD_DAC2_SET(0) | AD9154_PD_DAC3_SET(0) | + AD9154_PD_BG_SET(0)) + self.ad9154.dac_write(AD9154_TXENMASK1, AD9154_DACA_MASK_SET(0) | + AD9154_DACB_MASK_SET(0)) # TX not controlled by TXEN pins + self.ad9154.dac_write(AD9154_CLKCFG0, + AD9154_REF_CLKDIV_EN_SET(0) | AD9154_RF_SYNC_EN_SET(1) | + AD9154_DUTY_EN_SET(1) | AD9154_PD_CLK_REC_SET(0) | + AD9154_PD_SERDES_PCLK_SET(0) | AD9154_PD_CLK_DIG_SET(0) | + AD9154_PD_CLK23_SET(0) | AD9154_PD_CLK01_SET(0)) + self.ad9154.dac_write(AD9154_DACPLLCNTRL, + AD9154_ENABLE_DACPLL_SET(0) | AD9154_RECAL_DACPLL_SET(0)) + self.ad9154.dac_write(AD9154_SYSREF_ACTRL0, # jesd204b subclass 1 + AD9154_HYS_CNTRL1_SET(0) | AD9154_SYSREF_RISE_SET(0) | + AD9154_HYS_ON_SET(0) | AD9154_PD_SYSREF_BUFFER_SET(0)) + + self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_0, 0x8b) # magic + self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_1, 0x01) # magic + self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_2, 0x01) # magic + + 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_MIX_MODE, 0) + self.ad9154.dac_write(AD9154_DATA_FORMAT, AD9154_BINARY_FORMAT_SET(0)) # s16 + self.ad9154.dac_write(AD9154_DATAPATH_CTRL, + AD9154_I_TO_Q_SET(0) | AD9154_SEL_SIDEBAND_SET(0) | + AD9154_MODULATION_TYPE_SET(0) | AD9154_PHASE_ADJ_ENABLE_SET(0) | + AD9154_DIG_GAIN_ENABLE_SET(0) | AD9154_INVSINC_ENABLE_SET(0)) + self.ad9154.dac_write(AD9154_IDAC_DIG_GAIN0, 0x00) + self.ad9154.dac_write(AD9154_IDAC_DIG_GAIN1, 0x8) + self.ad9154.dac_write(AD9154_QDAC_DIG_GAIN0, 0x00) + self.ad9154.dac_write(AD9154_QDAC_DIG_GAIN1, 0x8) + self.ad9154.dac_write(AD9154_DC_OFFSET_CTRL, 0) + self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_1PART0, 0x00) + self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_1PART1, 0x00) + self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_2PART, 0x00) + self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_1PART0, 0x00) + self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_1PART1, 0x00) + self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_2PART, 0x00) + self.ad9154.dac_write(AD9154_PHASE_ADJ0, 0) + self.ad9154.dac_write(AD9154_PHASE_ADJ1, 0) + self.ad9154.dac_write(AD9154_GROUP_DLY, AD9154_COARSE_GROUP_DELAY_SET(0x8) | + AD9154_GROUP_DELAY_RESERVED_SET(0x8)) + self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_BYP, + AD9154_GROUPCOMP_BYPQ_SET(1) | + AD9154_GROUPCOMP_BYPI_SET(1)) + self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_I, 0) + self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_Q, 0) + self.ad9154.dac_write(AD9154_PDP_AVG_TIME, AD9154_PDP_ENABLE_SET(0)) + + self.ad9154.dac_write(AD9154_MASTER_PD, 0) + self.ad9154.dac_write(AD9154_PHY_PD, 0x0f) # power down lanes 0-3 + self.ad9154.dac_write(AD9154_GENERIC_PD, + AD9154_PD_SYNCOUT0B_SET(0) | + AD9154_PD_SYNCOUT1B_SET(1)) + self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_0, + AD9154_LINK_EN_SET(0x0) | AD9154_LINK_PAGE_SET(0) | + AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0)) + self.ad9154.dac_write(AD9154_ILS_DID, jesd_settings.did) + self.ad9154.dac_write(AD9154_ILS_BID, jesd_settings.bid) + self.ad9154.dac_write(AD9154_ILS_LID0, 0x00) # lane id + self.ad9154.dac_write(AD9154_ILS_SCR_L, + AD9154_L_1_SET(jesd_settings.phy.l - 1) | + AD9154_SCR_SET(1)) + self.ad9154.dac_write(AD9154_ILS_F, jesd_settings.transport.f - 1) + self.ad9154.dac_write(AD9154_ILS_K, jesd_settings.transport.k - 1) + self.ad9154.dac_write(AD9154_ILS_M, jesd_settings.phy.m - 1) + self.ad9154.dac_write(AD9154_ILS_CS_N, + AD9154_N_1_SET(jesd_settings.phy.n - 1) | + AD9154_CS_SET(0)) + self.ad9154.dac_write(AD9154_ILS_NP, + AD9154_NP_1_SET(jesd_settings.phy.np - 1) | + AD9154_SUBCLASSV_SET(jesd_settings.phy.subclassv)) + self.ad9154.dac_write(AD9154_ILS_S, + AD9154_S_1_SET(jesd_settings.transport.s - 1) | + AD9154_JESDV_SET(jesd_settings.phy.jesdv)) + self.ad9154.dac_write(AD9154_ILS_HD_CF, + AD9154_HD_SET(0) | AD9154_CF_SET(0)) + self.ad9154.dac_write(AD9154_ILS_CHECKSUM, jesd_checksum) + self.ad9154.dac_write(AD9154_LANEDESKEW, 0x0f) + for i in range(8): + self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_DIS_SET(0) | + AD9154_DISABLE_ERR_CNTR_DIS_SET(0) | + AD9154_RST_ERR_CNTR_DIS_SET(1) | AD9154_LANE_ADDR_DIS_SET(i)) + self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_DIS_SET(0) | + AD9154_DISABLE_ERR_CNTR_DIS_SET(0) | + AD9154_RST_ERR_CNTR_DIS_SET(0) | AD9154_LANE_ADDR_DIS_SET(i)) + self.ad9154.dac_write(AD9154_NIT_W, AD9154_RST_IRQ_NIT_SET(0) | + AD9154_DISABLE_ERR_CNTR_NIT_SET(0) | + AD9154_RST_ERR_CNTR_NIT_SET(1) | AD9154_LANE_ADDR_NIT_SET(i)) + self.ad9154.dac_write(AD9154_NIT_W, AD9154_RST_IRQ_NIT_SET(0) | + AD9154_DISABLE_ERR_CNTR_NIT_SET(0) | + AD9154_RST_ERR_CNTR_NIT_SET(0) | AD9154_LANE_ADDR_NIT_SET(i)) + self.ad9154.dac_write(AD9154_UNEXPECTEDCONTROL_W, AD9154_RST_IRQ_UCC_SET(0) | + AD9154_DISABLE_ERR_CNTR_UCC_SET(0) | + AD9154_RST_ERR_CNTR_UCC_SET(1) | AD9154_LANE_ADDR_UCC_SET(i)) + self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_UCC_SET(0) | + AD9154_DISABLE_ERR_CNTR_UCC_SET(0) | + AD9154_RST_ERR_CNTR_UCC_SET(0) | AD9154_LANE_ADDR_UCC_SET(i)) + self.ad9154.dac_write(AD9154_CTRLREG1, jesd_settings.transport.f) + self.ad9154.dac_write(AD9154_CTRLREG2, AD9154_ILAS_MODE_SET(0) | + AD9154_THRESHOLD_MASK_EN_SET(0)) + self.ad9154.dac_write(AD9154_KVAL, 1) # *4*K multiframes during ILAS + self.ad9154.dac_write(AD9154_LANEENABLE, 0x0f) + + self.ad9154.dac_write(AD9154_TERM_BLK1_CTRLREG0, 1) + self.ad9154.dac_write(AD9154_TERM_BLK2_CTRLREG0, 1) + self.ad9154.dac_write(AD9154_SERDES_SPI_REG, 1) + self.ad9154.dac_write(AD9154_CDR_OPERATING_MODE_REG_0, + AD9154_CDR_OVERSAMP_SET(0) | AD9154_CDR_RESERVED_SET(0x2) | + AD9154_ENHALFRATE_SET(0)) + self.ad9154.dac_write(AD9154_CDR_RESET, 0) + self.ad9154.dac_write(AD9154_CDR_RESET, 1) + self.ad9154.dac_write(AD9154_REF_CLK_DIVIDER_LDO, + AD9154_SPI_CDR_OVERSAMP_SET(0x1) | + AD9154_SPI_LDO_BYPASS_FILT_SET(1) | + AD9154_SPI_LDO_REF_SEL_SET(0)) + self.ad9154.dac_write(AD9154_LDO_FILTER_1, 0x62) # magic + self.ad9154.dac_write(AD9154_LDO_FILTER_2, 0xc9) # magic + self.ad9154.dac_write(AD9154_LDO_FILTER_3, 0x0e) # magic + self.ad9154.dac_write(AD9154_CP_CURRENT_SPI, + AD9154_SPI_CP_CURRENT_SET(0x12) | + AD9154_SPI_SERDES_LOGEN_POWER_MODE_SET(0)) + self.ad9154.dac_write(AD9154_VCO_LDO, 0x7b) # magic + self.ad9154.dac_write(AD9154_PLL_RD_REG, + AD9154_SPI_SERDES_LOGEN_PD_CORE_SET(0) | + AD9154_SPI_SERDES_LDO_PD_SET(0) | AD9154_SPI_SYN_PD_SET(0) | + AD9154_SPI_VCO_PD_ALC_SET(0) | AD9154_SPI_VCO_PD_PTAT_SET(0) | + AD9154_SPI_VCO_PD_SET(0)) + self.ad9154.dac_write(AD9154_ALC_VARACTOR, + AD9154_SPI_VCO_VARACTOR_SET(0x9) | + AD9154_SPI_INIT_ALC_VALUE_SET(0x8)) + self.ad9154.dac_write(AD9154_VCO_OUTPUT, + AD9154_SPI_VCO_OUTPUT_LEVEL_SET(0xc) | + AD9154_SPI_VCO_OUTPUT_RESERVED_SET(0x4)) + self.ad9154.dac_write(AD9154_CP_CONFIG, + AD9154_SPI_CP_TEST_SET(0) | + AD9154_SPI_CP_CAL_EN_SET(1) | + AD9154_SPI_CP_FORCE_CALBITS_SET(0) | + AD9154_SPI_CP_OFFSET_OFF_SET(0) | + AD9154_SPI_CP_ENABLE_MACHINE_SET(1) | + AD9154_SPI_CP_DITHER_MODE_SET(0) | + AD9154_SPI_CP_HALF_VCO_CAL_CLK_SET(0)) + self.ad9154.dac_write(AD9154_VCO_BIAS_1, + AD9154_SPI_VCO_BIAS_REF_SET(0x3) | + AD9154_SPI_VCO_BIAS_TCF_SET(0x3)) + self.ad9154.dac_write(AD9154_VCO_BIAS_2, + AD9154_SPI_PRESCALE_BIAS_SET(0x1) | + AD9154_SPI_LAST_ALC_EN_SET(1) | + AD9154_SPI_PRESCALE_BYPASS_R_SET(0x1) | + AD9154_SPI_VCO_COMP_BYPASS_BIASR_SET(0) | + AD9154_SPI_VCO_BYPASS_DAC_R_SET(0)) + self.ad9154.dac_write(AD9154_VCO_PD_OVERRIDES, + AD9154_SPI_VCO_PD_OVERRIDE_VCO_BUF_SET(0) | + AD9154_SPI_VCO_PD_OVERRIDE_CAL_TCF_SET(1) | + AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_TCF_SET(0) | + AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_SET(0)) + self.ad9154.dac_write(AD9154_VCO_CAL, + AD9154_SPI_FB_CLOCK_ADV_SET(0x2) | + AD9154_SPI_VCO_CAL_COUNT_SET(0x3) | + AD9154_SPI_VCO_CAL_ALC_WAIT_SET(0) | + AD9154_SPI_VCO_CAL_EN_SET(1)) + self.ad9154.dac_write(AD9154_CP_LEVEL_DETECT, + AD9154_SPI_CP_LEVEL_THRESHOLD_HIGH_SET(0x2) | + AD9154_SPI_CP_LEVEL_THRESHOLD_LOW_SET(0x5) | + AD9154_SPI_CP_LEVEL_DET_PD_SET(0)) + self.ad9154.dac_write(AD9154_VCO_VARACTOR_CTRL_0, + AD9154_SPI_VCO_VARACTOR_OFFSET_SET(0xe) | + AD9154_SPI_VCO_VARACTOR_REF_TCF_SET(0x7)) + self.ad9154.dac_write(AD9154_VCO_VARACTOR_CTRL_1, + AD9154_SPI_VCO_VARACTOR_REF_SET(0x6)) + # ensure link is txing + self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL, + AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(1)) + self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL, + AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(0)) + self.ad9154.dac_write(AD9154_EQ_BIAS_REG, AD9154_EQ_BIAS_RESERVED_SET(0x22) | + AD9154_EQ_POWER_MODE_SET(1)) + + self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_1, 1) # subclass 1 + self.ad9154.dac_write(AD9154_LMFC_DELAY_0, 0) + self.ad9154.dac_write(AD9154_LMFC_DELAY_1, 0) + self.ad9154.dac_write(AD9154_LMFC_VAR_0, 0x0a) # receive buffer delay + self.ad9154.dac_write(AD9154_LMFC_VAR_1, 0x0a) + self.ad9154.dac_write(AD9154_SYNC_ERRWINDOW, 0) # +- 1/2 DAC clock + self.ad9154.dac_write(AD9154_SYNC_CONTROL, + AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(0) | + AD9154_SYNCARM_SET(0)) + self.ad9154.dac_write(AD9154_SYNC_CONTROL, + AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(1) | + AD9154_SYNCARM_SET(0)) + self.ad9154.dac_write(AD9154_SYNC_CONTROL, + AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(1) | + AD9154_SYNCARM_SET(1)) + self.ad9154.dac_write(AD9154_XBAR_LN_0_1, + AD9154_LOGICAL_LANE0_SRC_SET(7) | AD9154_LOGICAL_LANE1_SRC_SET(6)) + self.ad9154.dac_write(AD9154_XBAR_LN_2_3, + AD9154_LOGICAL_LANE2_SRC_SET(5) | AD9154_LOGICAL_LANE3_SRC_SET(4)) + self.ad9154.dac_write(AD9154_XBAR_LN_4_5, + AD9154_LOGICAL_LANE4_SRC_SET(0) | AD9154_LOGICAL_LANE5_SRC_SET(0)) + self.ad9154.dac_write(AD9154_XBAR_LN_6_7, + AD9154_LOGICAL_LANE6_SRC_SET(0) | AD9154_LOGICAL_LANE7_SRC_SET(0)) + self.ad9154.dac_write(AD9154_JESD_BIT_INVERSE_CTRL, 0x00) + self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_0, + AD9154_LINK_EN_SET(0x1) | AD9154_LINK_PAGE_SET(0) | + AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0)) diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index 7ef671fab..2357b9fc9 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -1,29 +1,5 @@ -from jesd204b.common import (JESD204BPhysicalSettings, - JESD204BTransportSettings, - JESD204BSettings) from artiq.experiment import * from artiq.coredevice.ad9516_reg import * -from artiq.coredevice.ad9154_reg import * - -# ad9154 mode 2: -ps = JESD204BPhysicalSettings( - l=4, # lanes - m=4, # converters - n=16, # bits/converter - np=16, # bits/sample -) -ts = JESD204BTransportSettings( - f=2, # octets/(lane and frame) - s=1, # samples/(converter and frame) - k=16, # frames/multiframe - cs=1, # -) -jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) -jesd_checksum = jesd_settings.get_configuration_data()[-1] -# external clk=2000MHz -# pclock=250MHz -# deviceclock_fpga=500MHz -# deviceclock_dac=2000MHz class StartupKernel(EnvExperiment): @@ -38,12 +14,6 @@ class StartupKernel(EnvExperiment): self.ad9154.jesd_enable(0) self.ad9154.init() self.clock_setup() - self.dac_setup() - self.ad9154.jesd_prbs(0) - t = now_mu() + seconds_to_mu(.1*s) - while self.core.get_rtio_counter_mu() < t: - pass - self.ad9154.jesd_enable(1) @kernel def clock_setup(self): @@ -101,223 +71,3 @@ class StartupKernel(EnvExperiment): 0*AD9516_OUT7_SELECT_LVDS_CMOS) self.ad9154.clock_write(AD9516_UPDATE_ALL_REGISTERS, 1) - - @kernel - def dac_setup(self): - # reset - self.ad9154.dac_write(AD9154_SPI_INTFCONFA, AD9154_SOFTRESET_SET(1) | - AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1)) - self.ad9154.dac_write(AD9154_SPI_INTFCONFA, - AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1)) - if ((self.ad9154.dac_read(AD9154_PRODIDH) << 8) | - self.ad9154.dac_read(AD9154_PRODIDL) != 0x9154): - return - - self.ad9154.dac_write(AD9154_PWRCNTRL0, - AD9154_PD_DAC0_SET(0) | AD9154_PD_DAC1_SET(0) | - AD9154_PD_DAC2_SET(0) | AD9154_PD_DAC3_SET(0) | - AD9154_PD_BG_SET(0)) - self.ad9154.dac_write(AD9154_TXENMASK1, AD9154_DACA_MASK_SET(0) | - AD9154_DACB_MASK_SET(0)) # TX not controlled by TXEN pins - self.ad9154.dac_write(AD9154_CLKCFG0, - AD9154_REF_CLKDIV_EN_SET(0) | AD9154_RF_SYNC_EN_SET(1) | - AD9154_DUTY_EN_SET(1) | AD9154_PD_CLK_REC_SET(0) | - AD9154_PD_SERDES_PCLK_SET(0) | AD9154_PD_CLK_DIG_SET(0) | - AD9154_PD_CLK23_SET(0) | AD9154_PD_CLK01_SET(0)) - self.ad9154.dac_write(AD9154_DACPLLCNTRL, - AD9154_ENABLE_DACPLL_SET(0) | AD9154_RECAL_DACPLL_SET(0)) - self.ad9154.dac_write(AD9154_SYSREF_ACTRL0, # jesd204b subclass 1 - AD9154_HYS_CNTRL1_SET(0) | AD9154_SYSREF_RISE_SET(0) | - AD9154_HYS_ON_SET(0) | AD9154_PD_SYSREF_BUFFER_SET(0)) - - self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_0, 0x8b) # magic - self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_1, 0x01) # magic - self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_2, 0x01) # magic - - 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_MIX_MODE, 0) - self.ad9154.dac_write(AD9154_DATA_FORMAT, AD9154_BINARY_FORMAT_SET(0)) # s16 - self.ad9154.dac_write(AD9154_DATAPATH_CTRL, - AD9154_I_TO_Q_SET(0) | AD9154_SEL_SIDEBAND_SET(0) | - AD9154_MODULATION_TYPE_SET(0) | AD9154_PHASE_ADJ_ENABLE_SET(0) | - AD9154_DIG_GAIN_ENABLE_SET(0) | AD9154_INVSINC_ENABLE_SET(0)) - self.ad9154.dac_write(AD9154_IDAC_DIG_GAIN0, 0x00) - self.ad9154.dac_write(AD9154_IDAC_DIG_GAIN1, 0x8) - self.ad9154.dac_write(AD9154_QDAC_DIG_GAIN0, 0x00) - self.ad9154.dac_write(AD9154_QDAC_DIG_GAIN1, 0x8) - self.ad9154.dac_write(AD9154_DC_OFFSET_CTRL, 0) - self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_1PART0, 0x00) - self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_1PART1, 0x00) - self.ad9154.dac_write(AD9154_IPATH_DC_OFFSET_2PART, 0x00) - self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_1PART0, 0x00) - self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_1PART1, 0x00) - self.ad9154.dac_write(AD9154_QPATH_DC_OFFSET_2PART, 0x00) - self.ad9154.dac_write(AD9154_PHASE_ADJ0, 0) - self.ad9154.dac_write(AD9154_PHASE_ADJ1, 0) - self.ad9154.dac_write(AD9154_GROUP_DLY, AD9154_COARSE_GROUP_DELAY_SET(0x8) | - AD9154_GROUP_DELAY_RESERVED_SET(0x8)) - self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_BYP, - AD9154_GROUPCOMP_BYPQ_SET(1) | - AD9154_GROUPCOMP_BYPI_SET(1)) - self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_I, 0) - self.ad9154.dac_write(AD9154_GROUPDELAY_COMP_Q, 0) - self.ad9154.dac_write(AD9154_PDP_AVG_TIME, AD9154_PDP_ENABLE_SET(0)) - - self.ad9154.dac_write(AD9154_MASTER_PD, 0) - self.ad9154.dac_write(AD9154_PHY_PD, 0x0f) # power down lanes 0-3 - self.ad9154.dac_write(AD9154_GENERIC_PD, - AD9154_PD_SYNCOUT0B_SET(0) | - AD9154_PD_SYNCOUT1B_SET(1)) - self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_0, - AD9154_LINK_EN_SET(0x0) | AD9154_LINK_PAGE_SET(0) | - AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0)) - self.ad9154.dac_write(AD9154_ILS_DID, jesd_settings.did) - self.ad9154.dac_write(AD9154_ILS_BID, jesd_settings.bid) - self.ad9154.dac_write(AD9154_ILS_LID0, 0x00) # lane id - self.ad9154.dac_write(AD9154_ILS_SCR_L, - AD9154_L_1_SET(jesd_settings.phy.l - 1) | - AD9154_SCR_SET(1)) - self.ad9154.dac_write(AD9154_ILS_F, jesd_settings.transport.f - 1) - self.ad9154.dac_write(AD9154_ILS_K, jesd_settings.transport.k - 1) - self.ad9154.dac_write(AD9154_ILS_M, jesd_settings.phy.m - 1) - self.ad9154.dac_write(AD9154_ILS_CS_N, - AD9154_N_1_SET(jesd_settings.phy.n - 1) | - AD9154_CS_SET(0)) - self.ad9154.dac_write(AD9154_ILS_NP, - AD9154_NP_1_SET(jesd_settings.phy.np - 1) | - AD9154_SUBCLASSV_SET(jesd_settings.phy.subclassv)) - self.ad9154.dac_write(AD9154_ILS_S, - AD9154_S_1_SET(jesd_settings.transport.s - 1) | - AD9154_JESDV_SET(jesd_settings.phy.jesdv)) - self.ad9154.dac_write(AD9154_ILS_HD_CF, - AD9154_HD_SET(0) | AD9154_CF_SET(0)) - self.ad9154.dac_write(AD9154_ILS_CHECKSUM, jesd_checksum) - self.ad9154.dac_write(AD9154_LANEDESKEW, 0x0f) - for i in range(8): - self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_DIS_SET(0) | - AD9154_DISABLE_ERR_CNTR_DIS_SET(0) | - AD9154_RST_ERR_CNTR_DIS_SET(1) | AD9154_LANE_ADDR_DIS_SET(i)) - self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_DIS_SET(0) | - AD9154_DISABLE_ERR_CNTR_DIS_SET(0) | - AD9154_RST_ERR_CNTR_DIS_SET(0) | AD9154_LANE_ADDR_DIS_SET(i)) - self.ad9154.dac_write(AD9154_NIT_W, AD9154_RST_IRQ_NIT_SET(0) | - AD9154_DISABLE_ERR_CNTR_NIT_SET(0) | - AD9154_RST_ERR_CNTR_NIT_SET(1) | AD9154_LANE_ADDR_NIT_SET(i)) - self.ad9154.dac_write(AD9154_NIT_W, AD9154_RST_IRQ_NIT_SET(0) | - AD9154_DISABLE_ERR_CNTR_NIT_SET(0) | - AD9154_RST_ERR_CNTR_NIT_SET(0) | AD9154_LANE_ADDR_NIT_SET(i)) - self.ad9154.dac_write(AD9154_UNEXPECTEDCONTROL_W, AD9154_RST_IRQ_UCC_SET(0) | - AD9154_DISABLE_ERR_CNTR_UCC_SET(0) | - AD9154_RST_ERR_CNTR_UCC_SET(1) | AD9154_LANE_ADDR_UCC_SET(i)) - self.ad9154.dac_write(AD9154_BADDISPARITY, AD9154_RST_IRQ_UCC_SET(0) | - AD9154_DISABLE_ERR_CNTR_UCC_SET(0) | - AD9154_RST_ERR_CNTR_UCC_SET(0) | AD9154_LANE_ADDR_UCC_SET(i)) - self.ad9154.dac_write(AD9154_CTRLREG1, jesd_settings.transport.f) - self.ad9154.dac_write(AD9154_CTRLREG2, AD9154_ILAS_MODE_SET(0) | - AD9154_THRESHOLD_MASK_EN_SET(0)) - self.ad9154.dac_write(AD9154_KVAL, 1) # *4*K multiframes during ILAS - self.ad9154.dac_write(AD9154_LANEENABLE, 0x0f) - - self.ad9154.dac_write(AD9154_TERM_BLK1_CTRLREG0, 1) - self.ad9154.dac_write(AD9154_TERM_BLK2_CTRLREG0, 1) - self.ad9154.dac_write(AD9154_SERDES_SPI_REG, 1) - self.ad9154.dac_write(AD9154_CDR_OPERATING_MODE_REG_0, - AD9154_CDR_OVERSAMP_SET(0) | AD9154_CDR_RESERVED_SET(0x2) | - AD9154_ENHALFRATE_SET(0)) - self.ad9154.dac_write(AD9154_CDR_RESET, 0) - self.ad9154.dac_write(AD9154_CDR_RESET, 1) - self.ad9154.dac_write(AD9154_REF_CLK_DIVIDER_LDO, - AD9154_SPI_CDR_OVERSAMP_SET(0x1) | - AD9154_SPI_LDO_BYPASS_FILT_SET(1) | - AD9154_SPI_LDO_REF_SEL_SET(0)) - self.ad9154.dac_write(AD9154_LDO_FILTER_1, 0x62) # magic - self.ad9154.dac_write(AD9154_LDO_FILTER_2, 0xc9) # magic - self.ad9154.dac_write(AD9154_LDO_FILTER_3, 0x0e) # magic - self.ad9154.dac_write(AD9154_CP_CURRENT_SPI, - AD9154_SPI_CP_CURRENT_SET(0x12) | - AD9154_SPI_SERDES_LOGEN_POWER_MODE_SET(0)) - self.ad9154.dac_write(AD9154_VCO_LDO, 0x7b) # magic - self.ad9154.dac_write(AD9154_PLL_RD_REG, - AD9154_SPI_SERDES_LOGEN_PD_CORE_SET(0) | - AD9154_SPI_SERDES_LDO_PD_SET(0) | AD9154_SPI_SYN_PD_SET(0) | - AD9154_SPI_VCO_PD_ALC_SET(0) | AD9154_SPI_VCO_PD_PTAT_SET(0) | - AD9154_SPI_VCO_PD_SET(0)) - self.ad9154.dac_write(AD9154_ALC_VARACTOR, - AD9154_SPI_VCO_VARACTOR_SET(0x9) | - AD9154_SPI_INIT_ALC_VALUE_SET(0x8)) - self.ad9154.dac_write(AD9154_VCO_OUTPUT, - AD9154_SPI_VCO_OUTPUT_LEVEL_SET(0xc) | - AD9154_SPI_VCO_OUTPUT_RESERVED_SET(0x4)) - self.ad9154.dac_write(AD9154_CP_CONFIG, - AD9154_SPI_CP_TEST_SET(0) | - AD9154_SPI_CP_CAL_EN_SET(1) | - AD9154_SPI_CP_FORCE_CALBITS_SET(0) | - AD9154_SPI_CP_OFFSET_OFF_SET(0) | - AD9154_SPI_CP_ENABLE_MACHINE_SET(1) | - AD9154_SPI_CP_DITHER_MODE_SET(0) | - AD9154_SPI_CP_HALF_VCO_CAL_CLK_SET(0)) - self.ad9154.dac_write(AD9154_VCO_BIAS_1, - AD9154_SPI_VCO_BIAS_REF_SET(0x3) | - AD9154_SPI_VCO_BIAS_TCF_SET(0x3)) - self.ad9154.dac_write(AD9154_VCO_BIAS_2, - AD9154_SPI_PRESCALE_BIAS_SET(0x1) | - AD9154_SPI_LAST_ALC_EN_SET(1) | - AD9154_SPI_PRESCALE_BYPASS_R_SET(0x1) | - AD9154_SPI_VCO_COMP_BYPASS_BIASR_SET(0) | - AD9154_SPI_VCO_BYPASS_DAC_R_SET(0)) - self.ad9154.dac_write(AD9154_VCO_PD_OVERRIDES, - AD9154_SPI_VCO_PD_OVERRIDE_VCO_BUF_SET(0) | - AD9154_SPI_VCO_PD_OVERRIDE_CAL_TCF_SET(1) | - AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_TCF_SET(0) | - AD9154_SPI_VCO_PD_OVERRIDE_VAR_REF_SET(0)) - self.ad9154.dac_write(AD9154_VCO_CAL, - AD9154_SPI_FB_CLOCK_ADV_SET(0x2) | - AD9154_SPI_VCO_CAL_COUNT_SET(0x3) | - AD9154_SPI_VCO_CAL_ALC_WAIT_SET(0) | - AD9154_SPI_VCO_CAL_EN_SET(1)) - self.ad9154.dac_write(AD9154_CP_LEVEL_DETECT, - AD9154_SPI_CP_LEVEL_THRESHOLD_HIGH_SET(0x2) | - AD9154_SPI_CP_LEVEL_THRESHOLD_LOW_SET(0x5) | - AD9154_SPI_CP_LEVEL_DET_PD_SET(0)) - self.ad9154.dac_write(AD9154_VCO_VARACTOR_CTRL_0, - AD9154_SPI_VCO_VARACTOR_OFFSET_SET(0xe) | - AD9154_SPI_VCO_VARACTOR_REF_TCF_SET(0x7)) - self.ad9154.dac_write(AD9154_VCO_VARACTOR_CTRL_1, - AD9154_SPI_VCO_VARACTOR_REF_SET(0x6)) - # ensure link is txing - self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL, - AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(1)) - self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL, - AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(0)) - self.ad9154.dac_write(AD9154_EQ_BIAS_REG, AD9154_EQ_BIAS_RESERVED_SET(0x22) | - AD9154_EQ_POWER_MODE_SET(1)) - - self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_1, 1) # subclass 1 - self.ad9154.dac_write(AD9154_LMFC_DELAY_0, 0) - self.ad9154.dac_write(AD9154_LMFC_DELAY_1, 0) - self.ad9154.dac_write(AD9154_LMFC_VAR_0, 0x0a) # receive buffer delay - self.ad9154.dac_write(AD9154_LMFC_VAR_1, 0x0a) - self.ad9154.dac_write(AD9154_SYNC_ERRWINDOW, 0) # +- 1/2 DAC clock - self.ad9154.dac_write(AD9154_SYNC_CONTROL, - AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(0) | - AD9154_SYNCARM_SET(0)) - self.ad9154.dac_write(AD9154_SYNC_CONTROL, - AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(1) | - AD9154_SYNCARM_SET(0)) - self.ad9154.dac_write(AD9154_SYNC_CONTROL, - AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(1) | - AD9154_SYNCARM_SET(1)) - self.ad9154.dac_write(AD9154_XBAR_LN_0_1, - AD9154_LOGICAL_LANE0_SRC_SET(7) | AD9154_LOGICAL_LANE1_SRC_SET(6)) - self.ad9154.dac_write(AD9154_XBAR_LN_2_3, - AD9154_LOGICAL_LANE2_SRC_SET(5) | AD9154_LOGICAL_LANE3_SRC_SET(4)) - self.ad9154.dac_write(AD9154_XBAR_LN_4_5, - AD9154_LOGICAL_LANE4_SRC_SET(0) | AD9154_LOGICAL_LANE5_SRC_SET(0)) - self.ad9154.dac_write(AD9154_XBAR_LN_6_7, - AD9154_LOGICAL_LANE6_SRC_SET(0) | AD9154_LOGICAL_LANE7_SRC_SET(0)) - self.ad9154.dac_write(AD9154_JESD_BIT_INVERSE_CTRL, 0x00) - self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_0, - AD9154_LINK_EN_SET(0x1) | AD9154_LINK_PAGE_SET(0) | - AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0)) From 01bc7faacccb9f2c2b1e45dcc700e0dcfed410e2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 6 Oct 2016 17:27:50 +0200 Subject: [PATCH 011/157] dac_setup: cleanup, add doc --- README_PHASER.rst | 3 ++- artiq/examples/phaser/repository/dac_setup.py | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/README_PHASER.rst b/README_PHASER.rst index 9bd637b86..fe382c23d 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -97,7 +97,8 @@ Usage ----- * An example device database, several status and test scripts are provided in ``artiq/examples/phaser/``. -* run ``artiq_run sawg.py`` for an example that sets up amplitudes, frequencies, +* After each boot, run the ``dac_setup.py`` experiment to establish and align the data link (``artiq_run repository/dac_setup.py``). +* run ``artiq_run repository/sawg.py`` for an example that sets up amplitudes, frequencies, and phases on all four DDS channels. * Implement your own experiments using the SAWG channels. * Verify clock stability between the 2 GHz reference clock and the DAC outputs. diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index 50639d982..7d21175fd 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -38,18 +38,26 @@ class DACSetup(EnvExperiment): self.ad9154.init() self.dac_setup() self.ad9154.jesd_prbs(0) - t = now_mu() + seconds_to_mu(.1*s) + self.busywait_us(200000) + self.ad9154.jesd_enable(1) + while not self.ad9154.jesd_ready(): + pass + + @kernel + def busywait_us(self, t): + t = now_mu() + seconds_to_mu(t*us) while self.core.get_rtio_counter_mu() < t: pass - self.ad9154.jesd_enable(1) @kernel def dac_setup(self): # reset self.ad9154.dac_write(AD9154_SPI_INTFCONFA, AD9154_SOFTRESET_SET(1) | AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1)) + self.busywait_us(100) self.ad9154.dac_write(AD9154_SPI_INTFCONFA, AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1)) + self.busywait_us(100) if ((self.ad9154.dac_read(AD9154_PRODIDH) << 8) | self.ad9154.dac_read(AD9154_PRODIDL) != 0x9154): return @@ -58,6 +66,7 @@ class DACSetup(EnvExperiment): AD9154_PD_DAC0_SET(0) | AD9154_PD_DAC1_SET(0) | AD9154_PD_DAC2_SET(0) | AD9154_PD_DAC3_SET(0) | AD9154_PD_BG_SET(0)) + self.busywait_us(100) self.ad9154.dac_write(AD9154_TXENMASK1, AD9154_DACA_MASK_SET(0) | AD9154_DACB_MASK_SET(0)) # TX not controlled by TXEN pins self.ad9154.dac_write(AD9154_CLKCFG0, @@ -228,8 +237,8 @@ class DACSetup(EnvExperiment): self.ad9154.dac_write(AD9154_VCO_VARACTOR_CTRL_1, AD9154_SPI_VCO_VARACTOR_REF_SET(0x6)) # ensure link is txing - self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL, - AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(1)) + #self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL, + # AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(1)) self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL, AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(0)) self.ad9154.dac_write(AD9154_EQ_BIAS_REG, AD9154_EQ_BIAS_RESERVED_SET(0x22) | From 4390fea4377669d1f856af610a2d5afccaf3e7df Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 6 Oct 2016 17:36:54 +0200 Subject: [PATCH 012/157] phaser status: add statusmode stuff for serdes pll --- artiq/examples/phaser/repository/dac_setup.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index 7d21175fd..ba3376184 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -80,6 +80,13 @@ class DACSetup(EnvExperiment): AD9154_HYS_CNTRL1_SET(0) | AD9154_SYSREF_RISE_SET(0) | AD9154_HYS_ON_SET(0) | AD9154_PD_SYSREF_BUFFER_SET(0)) + self.ad9154.dac_write(AD9154_IRQEN_STATUSMODE0, + AD9154_IRQEN_SMODE_LANEFIFOERR_SET(1) | + AD9154_IRQEN_SMODE_SERPLLLOCK_SET(1) | + AD9154_IRQEN_SMODE_SERPLLLOST_SET(1) | + AD9154_IRQEN_SMODE_DACPLLLOCK_SET(1) | + AD9154_IRQEN_SMODE_DACPLLLOST_SET(1)) + self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_0, 0x8b) # magic self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_1, 0x01) # magic self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_2, 0x01) # magic From b02a7234f6885d94ed8135671a609d30b84ccdcf Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 7 Oct 2016 08:59:34 +0200 Subject: [PATCH 013/157] phaser: use 125MHz refclk for jesd --- artiq/examples/phaser/startup_kernel.py | 10 +++++++--- artiq/gateware/targets/kc705.py | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index 2357b9fc9..ecc31cd2a 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -1,3 +1,5 @@ +from math import ceil + from artiq.experiment import * from artiq.coredevice.ad9516_reg import * @@ -47,9 +49,11 @@ class StartupKernel(EnvExperiment): self.ad9154.clock_write(AD9516_OUT1, 0*AD9516_OUT1_POWER_DOWN | 2*AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE) - # FPGA deviceclk, dclk/1 - self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_1 | - AD9516_DIVIDER_4_BYPASS_2) + # FPGA deviceclk, dclk/4 + self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_2) + self.ad9154.clock_write(AD9516_DIVIDER_0_0, + (ceil(4/2)-1)*AD9516_DIVIDER_0_HIGH_CYCLES | + (4//2-1)*AD9516_DIVIDER_0_LOW_CYCLES) self.ad9154.clock_write(AD9516_DIVIDER_4_4, 1*AD9516_DIVIDER_4_DCCOFF) self.ad9154.clock_write(AD9516_OUT9, 1*AD9516_OUT9_LVDS_OUTPUT_CURRENT | 2*AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY | diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index d517756cc..ee6b87b1c 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -460,7 +460,7 @@ class AD9154(Module, AutoCSR): ts = JESD204BTransportSettings(f=2, s=1, k=16, cs=1) jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) jesd_linerate = 5e9 - jesd_refclk_freq = 500e6 + jesd_refclk_freq = 125e6 rtio_freq = 125*1000*1000 jesd_phys = [JESD204BPhyTX( rtio_crg.refclk, jesd_refclk_freq, From e998a980b3859ee84d08098c476f2eb00225401e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 7 Oct 2016 09:00:01 +0200 Subject: [PATCH 014/157] phaser/startup: use get_configuration_checksum() --- artiq/examples/phaser/repository/dac_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index ba3376184..ed6c0158d 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -18,7 +18,7 @@ ts = JESD204BTransportSettings( cs=1, # ) jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) -jesd_checksum = jesd_settings.get_configuration_data()[-1] +jesd_checksum = jesd_settings.get_configuration_checksum() # external clk=2000MHz # pclock=250MHz # deviceclock_fpga=500MHz From 09434ec054abe61c0d4cb9688776ae9d2a3f5dca Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Oct 2016 12:44:22 +0200 Subject: [PATCH 015/157] phaser: also adapt rtio_crg --- artiq/gateware/targets/kc705.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index ee6b87b1c..f65cbefa4 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -392,8 +392,6 @@ class NIST_QC2(_NIST_Ions): class _PhaserCRG(Module, AutoCSR): def __init__(self, platform, rtio_internal_clk): - rtio_internal_clk = ClockSignal("sys4x") - self._clock_sel = CSRStorage() self._pll_reset = CSRStorage(reset=1) self._pll_locked = CSRStatus() @@ -401,7 +399,7 @@ class _PhaserCRG(Module, AutoCSR): self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) refclk_pads = platform.request("ad9154_refclk") - platform.add_period_constraint(refclk_pads.p, 2.) + platform.add_period_constraint(refclk_pads.p, 5.) self.refclk = Signal() self.clock_domains.cd_refclk = ClockDomain() self.specials += [ @@ -419,12 +417,12 @@ class _PhaserCRG(Module, AutoCSR): p_REF_JITTER1=0.01, p_REF_JITTER2=0.01, p_CLKIN1_PERIOD=2.0, p_CLKIN2_PERIOD=2.0, - i_CLKIN1=rtio_internal_clk, i_CLKIN2=self.cd_refclk.clk, + i_CLKIN1=rtio_internal_clk, i_CLKIN2=self.refclk, # Warning: CLKINSEL=0 means CLKIN2 is selected i_CLKINSEL=~self._clock_sel.storage, - # VCO @ 1GHz when using 500MHz input - p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=4, + # 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, From c846e758f154c450d051100c8c10621c55131be4 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Oct 2016 12:57:38 +0200 Subject: [PATCH 016/157] phaser: fix startup_kernel/ceil --- artiq/examples/phaser/startup_kernel.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index ecc31cd2a..db0c7bdb1 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -1,5 +1,3 @@ -from math import ceil - from artiq.experiment import * from artiq.coredevice.ad9516_reg import * @@ -52,7 +50,7 @@ class StartupKernel(EnvExperiment): # FPGA deviceclk, dclk/4 self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_2) self.ad9154.clock_write(AD9516_DIVIDER_0_0, - (ceil(4/2)-1)*AD9516_DIVIDER_0_HIGH_CYCLES | + (4//2-1)*AD9516_DIVIDER_0_HIGH_CYCLES | (4//2-1)*AD9516_DIVIDER_0_LOW_CYCLES) self.ad9154.clock_write(AD9516_DIVIDER_4_4, 1*AD9516_DIVIDER_4_DCCOFF) self.ad9154.clock_write(AD9516_OUT9, 1*AD9516_OUT9_LVDS_OUTPUT_CURRENT | From 9b860b26e85d2b545d8763ced04838b81ed56087 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Oct 2016 13:00:42 +0200 Subject: [PATCH 017/157] phaser: fix rtio pll inputs --- artiq/gateware/targets/kc705.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index f65cbefa4..84d77907a 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -416,8 +416,8 @@ class _PhaserCRG(Module, AutoCSR): p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, p_REF_JITTER1=0.01, p_REF_JITTER2=0.01, - p_CLKIN1_PERIOD=2.0, p_CLKIN2_PERIOD=2.0, - i_CLKIN1=rtio_internal_clk, i_CLKIN2=self.refclk, + p_CLKIN1_PERIOD=5.0, p_CLKIN2_PERIOD=5.0, + i_CLKIN1=rtio_internal_clk, i_CLKIN2=self.cd_refclk.clk, # Warning: CLKINSEL=0 means CLKIN2 is selected i_CLKINSEL=~self._clock_sel.storage, From cfd2fe862707fed6ebd08be89f3495080fd8c8a7 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Oct 2016 13:40:45 +0200 Subject: [PATCH 018/157] phaser: fix fpga deviceclock divider --- artiq/examples/phaser/startup_kernel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index db0c7bdb1..eb310ddf5 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -49,7 +49,7 @@ class StartupKernel(EnvExperiment): # FPGA deviceclk, dclk/4 self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_2) - self.ad9154.clock_write(AD9516_DIVIDER_0_0, + self.ad9154.clock_write(AD9516_DIVIDER_4_0, (4//2-1)*AD9516_DIVIDER_0_HIGH_CYCLES | (4//2-1)*AD9516_DIVIDER_0_LOW_CYCLES) self.ad9154.clock_write(AD9516_DIVIDER_4_4, 1*AD9516_DIVIDER_4_DCCOFF) From 72932fccec813b231e6f7bd644078d33ee76f5f9 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Oct 2016 15:40:00 +0200 Subject: [PATCH 019/157] phaser: fix sysref for 250 MHz sample rate --- artiq/examples/phaser/startup_kernel.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index eb310ddf5..24b5b3fb5 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -57,13 +57,15 @@ class StartupKernel(EnvExperiment): 2*AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY | 0*AD9516_OUT9_SELECT_LVDS_CMOS) - # sysref f_data*S/(K*F), dclk/32 - self.ad9154.clock_write(AD9516_DIVIDER_3_0, 15*AD9516_DIVIDER_3_HIGH_CYCLES_1 | - 15*AD9516_DIVIDER_3_LOW_CYCLES_1) + # sysref f_data*S/(K*F), dclk/64 + 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) self.ad9154.clock_write(AD9516_DIVIDER_3_1, 0*AD9516_DIVIDER_3_PHASE_OFFSET_1 | 0*AD9516_DIVIDER_3_PHASE_OFFSET_2) + self.ad9154.clock_write(AD9516_DIVIDER_3_2, (2//2-1)*AD9516_DIVIDER_3_HIGH_CYCLES_2 | + (2//2-1)*AD9516_DIVIDER_3_LOW_CYCLES_2) self.ad9154.clock_write(AD9516_DIVIDER_3_3, 0*AD9516_DIVIDER_3_NOSYNC | - 0*AD9516_DIVIDER_3_BYPASS_1 | 1*AD9516_DIVIDER_3_BYPASS_2) + 0*AD9516_DIVIDER_3_BYPASS_1 | 0*AD9516_DIVIDER_3_BYPASS_2) self.ad9154.clock_write(AD9516_DIVIDER_3_4, 1*AD9516_DIVIDER_3_DCCOFF) self.ad9154.clock_write(AD9516_OUT6, 1*AD9516_OUT6_LVDS_OUTPUT_CURRENT | 2*AD9516_OUT6_LVDS_CMOS_OUTPUT_POLARITY | From 1157a3a54b5f691db818be5ee24609879c49e439 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Oct 2016 15:42:46 +0200 Subject: [PATCH 020/157] ad9514_status: more info --- artiq/examples/phaser/repository/test_ad9154_status.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/artiq/examples/phaser/repository/test_ad9154_status.py b/artiq/examples/phaser/repository/test_ad9154_status.py index 58c16da93..6c401155c 100644 --- a/artiq/examples/phaser/repository/test_ad9154_status.py +++ b/artiq/examples/phaser/repository/test_ad9154_status.py @@ -80,6 +80,11 @@ class Test(EnvExperiment): self.p("GOODCHECKSUM: 0x%02x", self.ad9154.dac_read(AD9154_GOODCHKSUMFLG)) self.p("INITIALLANESYNC: 0x%02x", self.ad9154.dac_read(AD9154_INITLANESYNCFLG)) + x = self.ad9154.dac_read(AD9154_SYNC_CURRERR_H) + self.p("SYNC_CURRERR: 0x%04x", self.ad9154.dac_read(AD9154_SYNC_CURRERR_L) | + (AD9154_CURRERROR_H_GET(x) << 8)) + self.p("SYNC_CURROVER: %d, SYNC_CURRUNDER: %d", + AD9154_CURROVER_GET(x), AD9154_CURRUNDER_GET(x)) x = self.ad9154.dac_read(AD9154_SYNC_LASTERR_H) self.p("SYNC_LASTERR: 0x%04x", self.ad9154.dac_read(AD9154_SYNC_LASTERR_L) | (AD9154_LASTERROR_H_GET(x) << 8)) @@ -124,3 +129,7 @@ class Test(EnvExperiment): self.p("BADDISPARITY: 0x%02x", self.ad9154.dac_read(AD9154_BADDISPARITY)) self.p("NITDISPARITY: 0x%02x", self.ad9154.dac_read(AD9154_NIT_W)) self.p("UNEXPECTEDCONTROL: 0x%02x", self.ad9154.dac_read(AD9154_UNEXPECTEDCONTROL_W)) + self.p("DYN_LINK_LATENCY_0: 0x%02x", + self.ad9154.dac_read(AD9154_DYN_LINK_LATENCY_0)) + self.p("DYN_LINK_LATENCY_1: 0x%02x", + self.ad9154.dac_read(AD9154_DYN_LINK_LATENCY_1)) From 4e60a6ac71a8ffbd8edb538d7e0b7bfce2932b46 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 8 Oct 2016 00:02:24 +0800 Subject: [PATCH 021/157] phaser: tweak sawg example --- artiq/examples/phaser/repository/sawg.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/examples/phaser/repository/sawg.py b/artiq/examples/phaser/repository/sawg.py index 6c13d5b9a..3e276a240 100644 --- a/artiq/examples/phaser/repository/sawg.py +++ b/artiq/examples/phaser/repository/sawg.py @@ -13,17 +13,17 @@ class SAWGTest(EnvExperiment): @kernel def run(self): - self.core.reset() - + self.core.break_realtime() delay(100*us) + self.sawg0.set_amplitude(.1) - self.sawg1.set_amplitude(-1.) + self.sawg1.set_amplitude(-.9) self.sawg2.set_amplitude(.5) self.sawg3.set_amplitude(.5) self.sawg0.set_frequency(1*MHz) - self.sawg1.set_frequency(100*MHz) - self.sawg2.set_frequency(200*MHz) - self.sawg3.set_frequency(200*MHz) + self.sawg1.set_frequency(10*MHz) + self.sawg2.set_frequency(20*MHz) + self.sawg3.set_frequency(20*MHz) self.sawg0.set_phase(0.) self.sawg1.set_phase(0.) self.sawg2.set_phase(0.) From 89a30b6f7cdc93414939122daa6292b3f9ac7801 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 8 Oct 2016 00:02:38 +0800 Subject: [PATCH 022/157] phaser: error on startup kernel --- artiq/examples/phaser/startup_kernel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index 24b5b3fb5..1246da37b 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -26,7 +26,7 @@ class StartupKernel(EnvExperiment): AD9516_LONG_INSTRUCTION | AD9516_LONG_INSTRUCTION_MIRRORED | AD9516_SDO_ACTIVE | AD9516_SDO_ACTIVE_MIRRORED) if self.ad9154.clock_read(AD9516_PART_ID) != 0x41: - return + raise ValueError("AD9516 not found") # use clk input, dclk=clk/4 self.ad9154.clock_write(AD9516_PFD_AND_CHARGE_PUMP, 1*AD9516_PLL_POWER_DOWN | From 1f9365872483cfa10c97a99a68106e5b63087cd3 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 7 Oct 2016 18:54:21 +0200 Subject: [PATCH 023/157] phaser/dac_setup: clear sticky bits, use syncmode=9 --- artiq/examples/phaser/repository/dac_setup.py | 75 +++++++++++++++---- 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index ed6c0158d..2a8297139 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -33,11 +33,11 @@ class DACSetup(EnvExperiment): @kernel def run(self): - self.core.reset() + self.core.break_realtime() self.ad9154.jesd_enable(0) + self.ad9154.jesd_prbs(0) self.ad9154.init() self.dac_setup() - self.ad9154.jesd_prbs(0) self.busywait_us(200000) self.ad9154.jesd_enable(1) while not self.ad9154.jesd_ready(): @@ -60,7 +60,7 @@ class DACSetup(EnvExperiment): self.busywait_us(100) if ((self.ad9154.dac_read(AD9154_PRODIDH) << 8) | self.ad9154.dac_read(AD9154_PRODIDL) != 0x9154): - return + raise ValueError("AD9154 not found") self.ad9154.dac_write(AD9154_PWRCNTRL0, AD9154_PD_DAC0_SET(0) | AD9154_PD_DAC1_SET(0) | @@ -80,13 +80,6 @@ class DACSetup(EnvExperiment): AD9154_HYS_CNTRL1_SET(0) | AD9154_SYSREF_RISE_SET(0) | AD9154_HYS_ON_SET(0) | AD9154_PD_SYSREF_BUFFER_SET(0)) - self.ad9154.dac_write(AD9154_IRQEN_STATUSMODE0, - AD9154_IRQEN_SMODE_LANEFIFOERR_SET(1) | - AD9154_IRQEN_SMODE_SERPLLLOCK_SET(1) | - AD9154_IRQEN_SMODE_SERPLLLOST_SET(1) | - AD9154_IRQEN_SMODE_DACPLLLOCK_SET(1) | - AD9154_IRQEN_SMODE_DACPLLLOST_SET(1)) - self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_0, 0x8b) # magic self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_1, 0x01) # magic self.ad9154.dac_write(AD9154_DEVICE_CONFIG_REG_2, 0x01) # magic @@ -258,14 +251,21 @@ class DACSetup(EnvExperiment): self.ad9154.dac_write(AD9154_LMFC_VAR_1, 0x0a) self.ad9154.dac_write(AD9154_SYNC_ERRWINDOW, 0) # +- 1/2 DAC clock self.ad9154.dac_write(AD9154_SYNC_CONTROL, - AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(0) | - AD9154_SYNCARM_SET(0)) + AD9154_SYNCMODE_SET(0x9) | AD9154_SYNCENABLE_SET(0) | + AD9154_SYNCARM_SET(0) | AD9154_SYNCCLRSTKY_SET(1) | + AD9154_SYNCCLRLAST_SET(1)) self.ad9154.dac_write(AD9154_SYNC_CONTROL, - AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(1) | - AD9154_SYNCARM_SET(0)) + AD9154_SYNCMODE_SET(0x9) | AD9154_SYNCENABLE_SET(1) | + AD9154_SYNCARM_SET(0) | AD9154_SYNCCLRSTKY_SET(1) | + AD9154_SYNCCLRLAST_SET(1)) self.ad9154.dac_write(AD9154_SYNC_CONTROL, - AD9154_SYNCMODE_SET(1) | AD9154_SYNCENABLE_SET(1) | - AD9154_SYNCARM_SET(1)) + AD9154_SYNCMODE_SET(0x9) | AD9154_SYNCENABLE_SET(1) | + AD9154_SYNCARM_SET(1) | AD9154_SYNCCLRSTKY_SET(0) | + AD9154_SYNCCLRLAST_SET(0)) + self.busywait_us(1000) # ensure at leas one sysref edge + if not AD9154_SYNC_LOCK_GET(self.ad9154.dac_read(AD9154_SYNC_STATUS)): + pass + # raise ValueError("no sync lock") self.ad9154.dac_write(AD9154_XBAR_LN_0_1, AD9154_LOGICAL_LANE0_SRC_SET(7) | AD9154_LOGICAL_LANE1_SRC_SET(6)) self.ad9154.dac_write(AD9154_XBAR_LN_2_3, @@ -278,3 +278,46 @@ class DACSetup(EnvExperiment): self.ad9154.dac_write(AD9154_GENERAL_JRX_CTRL_0, AD9154_LINK_EN_SET(0x1) | AD9154_LINK_PAGE_SET(0) | AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0)) + + self.busywait_us(1000) + + self.ad9154.dac_write(AD9154_IRQ_STATUS0, 0x00) + self.ad9154.dac_write(AD9154_IRQ_STATUS1, 0x00) + self.ad9154.dac_write(AD9154_IRQ_STATUS2, 0x00) + self.ad9154.dac_write(AD9154_IRQ_STATUS3, 0x00) + + self.ad9154.dac_write(AD9154_IRQEN_STATUSMODE0, + AD9154_IRQEN_SMODE_LANEFIFOERR_SET(1) | + AD9154_IRQEN_SMODE_SERPLLLOCK_SET(1) | + AD9154_IRQEN_SMODE_SERPLLLOST_SET(1) | + AD9154_IRQEN_SMODE_DACPLLLOCK_SET(1) | + AD9154_IRQEN_SMODE_DACPLLLOST_SET(1)) + + self.ad9154.dac_write(AD9154_IRQEN_STATUSMODE1, + AD9154_IRQEN_SMODE_PRBS0_SET(1) | + AD9154_IRQEN_SMODE_PRBS1_SET(1) | + AD9154_IRQEN_SMODE_PRBS2_SET(1) | + AD9154_IRQEN_SMODE_PRBS3_SET(1)) + + self.ad9154.dac_write(AD9154_IRQEN_STATUSMODE2, + AD9154_IRQEN_SMODE_SYNC_TRIP0_SET(1) | + AD9154_IRQEN_SMODE_SYNC_WLIM0_SET(1) | + AD9154_IRQEN_SMODE_SYNC_ROTATE0_SET(1) | + AD9154_IRQEN_SMODE_SYNC_LOCK0_SET(1) | + AD9154_IRQEN_SMODE_NCO_ALIGN0_SET(1) | + AD9154_IRQEN_SMODE_BLNKDONE0_SET(1) | + AD9154_IRQEN_SMODE_PDPERR0_SET(1)) + + self.ad9154.dac_write(AD9154_IRQEN_STATUSMODE3, + AD9154_IRQEN_SMODE_SYNC_TRIP1_SET(1) | + AD9154_IRQEN_SMODE_SYNC_WLIM1_SET(1) | + AD9154_IRQEN_SMODE_SYNC_ROTATE1_SET(1) | + AD9154_IRQEN_SMODE_SYNC_LOCK1_SET(1) | + AD9154_IRQEN_SMODE_NCO_ALIGN1_SET(1) | + AD9154_IRQEN_SMODE_BLNKDONE1_SET(1) | + AD9154_IRQEN_SMODE_PDPERR1_SET(1)) + + self.ad9154.dac_write(AD9154_IRQ_STATUS0, 0x00) + self.ad9154.dac_write(AD9154_IRQ_STATUS1, 0x00) + self.ad9154.dac_write(AD9154_IRQ_STATUS2, 0x00) + self.ad9154.dac_write(AD9154_IRQ_STATUS3, 0x00) From 5f7229ef9233441d576515817cd2012e14e1fafe Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 9 Oct 2016 20:34:15 +0200 Subject: [PATCH 024/157] ad9154: tweak jesd prbs test --- artiq/examples/phaser/repository/test_ad9154_prbs.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/artiq/examples/phaser/repository/test_ad9154_prbs.py b/artiq/examples/phaser/repository/test_ad9154_prbs.py index 887b45d29..337da468f 100644 --- a/artiq/examples/phaser/repository/test_ad9154_prbs.py +++ b/artiq/examples/phaser/repository/test_ad9154_prbs.py @@ -10,12 +10,15 @@ class Test(EnvExperiment): self.setattr_device("ad9154") def run(self): - self.prbs(2, 100) # prbs31 + for i in range(3): # prbs7, prbs15, prbs31 + self.prbs(i, 100) def p(self, f, *a): print(f % a) - def prbs(self, p, t): + def prbs(self, p, t, inject_errors=0): + self.ad9154.jesd_prbs((1 << p) | (inject_errors << 3)) + self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, AD9154_PHY_PRBS_PAT_SEL_SET(p)) self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_EN, 0xff) From c08caae171dcb5f57e1de688ea451dc70ead99e4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 10 Oct 2016 17:05:42 +0200 Subject: [PATCH 025/157] phaser: use qpll --- artiq/gateware/targets/kc705.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 84d77907a..257dc381f 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -14,6 +14,7 @@ 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 @@ -460,11 +461,12 @@ class AD9154(Module, AutoCSR): jesd_linerate = 5e9 jesd_refclk_freq = 125e6 rtio_freq = 125*1000*1000 + jesd_qpll = GTXQuadPLL( + rtio_crg.refclk, jesd_refclk_freq, jesd_linerate) jesd_phys = [JESD204BPhyTX( - rtio_crg.refclk, jesd_refclk_freq, - platform.request("ad9154_jesd", i), - jesd_linerate, rtio_freq, i) for i in range(4)] - self.submodules += jesd_phys + jesd_qpll, platform.request("ad9154_jesd", i), + rtio_freq, i) for i in range(4)] + self.submodules += jesd_qpll, jesd_phys for jesd_phy in jesd_phys: platform.add_period_constraint( jesd_phy.gtx.cd_tx.clk, From e27228fdd508394e470b17885f1f388004d8b8ab Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 9 Oct 2016 23:20:03 +0800 Subject: [PATCH 026/157] ad9516: duty cycle correction --- artiq/examples/phaser/startup_kernel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index 1246da37b..089d49d92 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -52,7 +52,7 @@ class StartupKernel(EnvExperiment): self.ad9154.clock_write(AD9516_DIVIDER_4_0, (4//2-1)*AD9516_DIVIDER_0_HIGH_CYCLES | (4//2-1)*AD9516_DIVIDER_0_LOW_CYCLES) - self.ad9154.clock_write(AD9516_DIVIDER_4_4, 1*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 | 2*AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY | 0*AD9516_OUT9_SELECT_LVDS_CMOS) @@ -66,7 +66,7 @@ class StartupKernel(EnvExperiment): (2//2-1)*AD9516_DIVIDER_3_LOW_CYCLES_2) self.ad9154.clock_write(AD9516_DIVIDER_3_3, 0*AD9516_DIVIDER_3_NOSYNC | 0*AD9516_DIVIDER_3_BYPASS_1 | 0*AD9516_DIVIDER_3_BYPASS_2) - self.ad9154.clock_write(AD9516_DIVIDER_3_4, 1*AD9516_DIVIDER_3_DCCOFF) + self.ad9154.clock_write(AD9516_DIVIDER_3_4, 0*AD9516_DIVIDER_3_DCCOFF) self.ad9154.clock_write(AD9516_OUT6, 1*AD9516_OUT6_LVDS_OUTPUT_CURRENT | 2*AD9516_OUT6_LVDS_CMOS_OUTPUT_POLARITY | 0*AD9516_OUT6_SELECT_LVDS_CMOS) From f5f7acc1f8bfb8cd1ff17fefc7e4cf1e744f97a2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 10 Oct 2016 16:12:28 +0200 Subject: [PATCH 027/157] ttl_simple: add pure Input (no Tristate for internal signals) --- artiq/gateware/rtio/phy/ttl_simple.py | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/artiq/gateware/rtio/phy/ttl_simple.py b/artiq/gateware/rtio/phy/ttl_simple.py index 2192758df..85c03af6d 100644 --- a/artiq/gateware/rtio/phy/ttl_simple.py +++ b/artiq/gateware/rtio/phy/ttl_simple.py @@ -27,6 +27,43 @@ class Output(Module): ] +class Input(Module): + def __init__(self, pad): + self.rtlink = rtlink.Interface( + rtlink.OInterface(2, 2), + rtlink.IInterface(1)) + self.overrides = [] + self.probes = [] + + # # # + + sensitivity = Signal(2) + + sample = Signal() + self.sync.rio += [ + sample.eq(0), + If(self.rtlink.o.stb & self.rtlink.o.address[1], + sensitivity.eq(self.rtlink.o.data), + If(self.rtlink.o.address[0], sample.eq(1)) + ) + ] + + i = Signal() + i_d = Signal() + self.specials += MultiReg(pad, i, "rio_phy") + self.sync.rio_phy += i_d.eq(i) + self.comb += [ + self.rtlink.i.stb.eq( + sample | + (sensitivity[0] & ( i & ~i_d)) | + (sensitivity[1] & (~i & i_d)) + ), + self.rtlink.i.data.eq(i) + ] + + self.probes += [i] + + class Inout(Module): def __init__(self, pad): self.rtlink = rtlink.Interface( From 18d18b668569104a4735ee06b1d253171c7f1119 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 10 Oct 2016 16:13:50 +0200 Subject: [PATCH 028/157] phaser: add sync ttl input for monitoring --- artiq/examples/phaser/device_db.pyon | 14 ++++++++++---- artiq/gateware/targets/kc705.py | 19 +++++++++++++------ doc/manual/core_device.rst | 4 +++- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/artiq/examples/phaser/device_db.pyon b/artiq/examples/phaser/device_db.pyon index f1b441921..c9bfe06f5 100644 --- a/artiq/examples/phaser/device_db.pyon +++ b/artiq/examples/phaser/device_db.pyon @@ -44,28 +44,34 @@ "class": "TTLInOut", "arguments": {"channel": 2} }, + "sync": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 3} + }, "sawg0": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 3, "parallelism": 4} + "arguments": {"channel_base": 4, "parallelism": 4} }, "sawg1": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 6, "parallelism": 4} + "arguments": {"channel_base": 7, "parallelism": 4} }, "sawg2": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 9, "parallelism": 4} + "arguments": {"channel_base": 10, "parallelism": 4} }, "sawg3": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 12, "parallelism": 4} + "arguments": {"channel_base": 13, "parallelism": 4} } } diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 257dc381f..67bdc2ab8 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -149,8 +149,10 @@ class _NIST_Ions(MiniSoC, AMPSoC): self.register_kernel_cpu_csrdevice("i2c") self.config["I2C_BUS_COUNT"] = 1 - def add_rtio(self, rtio_channels, crg=_RTIOCRG): - self.submodules.rtio_crg = crg(self.platform, self.crg.cd_sys.clk) + def add_rtio(self, rtio_channels, rtio_crg=None): + if rtio_crg is None: + rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) + self.submodules.rtio_crg = rtio_crg self.csr_devices.append("rtio_crg") self.submodules.rtio = rtio.RTIO(rtio_channels) self.register_kernel_cpu_csrdevice("rtio") @@ -454,6 +456,7 @@ class AD9154(Module, AutoCSR): 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) ts = JESD204BTransportSettings(f=2, s=1, k=16, cs=1) @@ -510,6 +513,12 @@ class Phaser(_NIST_Ions): rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32, ofifo_depth=2)) + jesd_sync = Signal() + phy = ttl_simple.Input(jesd_sync) + 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) @@ -522,11 +531,8 @@ class Phaser(_NIST_Ions): self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) - self.add_rtio(rtio_channels, _PhaserCRG) + self.add_rtio(rtio_channels, _PhaserCRG(platform, self.crg.cd_sys.clk)) - # jesd_sysref = Signal() - # self.specials += DifferentialInput( - # sysref_pads.p, sysref_pads.n, jesd_sysref) to_rtio = ClockDomainsRenamer({"sys": "rtio"}) self.submodules.ad9154 = to_rtio(AD9154(platform, self.rtio_crg)) self.register_kernel_cpu_csrdevice("ad9154") @@ -537,6 +543,7 @@ class Phaser(_NIST_Ions): "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(): diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index 7f48d719a..389e11fa4 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -170,8 +170,10 @@ The Phaser adapter is an AD9154-FMC-EBZ, a 4 channel 2.4 GHz DAC on an FMC HPC c +--------------+------------+--------------+ | 2 | SYSREF | Input | +--------------+------------+--------------+ +| 3 | SYNC | Input | ++--------------+------------+--------------+ -The SAWG channels start with RTIO channel number 3, each occupying 3 channels. +The SAWG channels start with RTIO channel number 4, each occupying 3 channels. The board has one non-RTIO SPI bus that is accessible through :mod:`artiq.coredevice.ad9154`. From e4d1f6cf1f1fed390c5caa101203b0f3fd30614d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 10 Oct 2016 18:49:24 +0200 Subject: [PATCH 029/157] README_PHASER: update --- README_PHASER.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README_PHASER.rst b/README_PHASER.rst index fe382c23d..31558ab5a 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -38,9 +38,15 @@ Please refer to the manual for more details: https://m-labs.hk/artiq/manual-release-2/index.html * Set up a new conda environment and activate it. -* Checkout the ARTIQ phaser branch: :: +* Checkout the ARTIQ phaser branch and the JESD204B core: :: + mkdir ~/src + cd ~/src git clone --recursive -b phaser https://github.com/m-labs/artiq.git + git clone https://github.com/m-labs/jesd204b.git + cd jesd204b + python setup.py develop + cd ../artiq * Install the standard ARTIQ runtime/install dependencies. See ``conda/artiq/meta.yaml`` for a list. From 2b1cca2e7e6dabdab07fd5198c4e7f8cb6a6c7ca Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 11 Oct 2016 19:23:13 +0200 Subject: [PATCH 030/157] phaser: stpl --- .../phaser/repository/test_ad9154_stpl.py | 45 +++++++++++++++++++ artiq/gateware/targets/kc705.py | 9 ++++ 2 files changed, 54 insertions(+) create mode 100644 artiq/examples/phaser/repository/test_ad9154_stpl.py diff --git a/artiq/examples/phaser/repository/test_ad9154_stpl.py b/artiq/examples/phaser/repository/test_ad9154_stpl.py new file mode 100644 index 000000000..bc5cc40c4 --- /dev/null +++ b/artiq/examples/phaser/repository/test_ad9154_stpl.py @@ -0,0 +1,45 @@ +import time + +from artiq.coredevice.ad9154_reg import * +from artiq.experiment import * + + +class Test(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("ad9154") + + def run(self): + self.stpl() + + def stpl(self): + # short transport layer test + for i, data in enumerate([0x0123, 0x4567, 0x89ab, 0xcdef]): + # select dac + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, + AD9154_SHORT_TPL_TEST_EN_SET(0) | + AD9154_SHORT_TPL_TEST_RESET_SET(0) | + AD9154_SHORT_TPL_DAC_SEL_SET(i) | + AD9154_SHORT_TPL_SP_SEL_SET(0)) + # set expected value + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_2, data & 0xff) + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_1, (data & 0xff00) >> 8) + # enable stpl + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, + AD9154_SHORT_TPL_TEST_EN_SET(1) | + AD9154_SHORT_TPL_TEST_RESET_SET(0) | + AD9154_SHORT_TPL_DAC_SEL_SET(i) | + AD9154_SHORT_TPL_SP_SEL_SET(0)) + # reset stpl + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, + AD9154_SHORT_TPL_TEST_EN_SET(1) | + AD9154_SHORT_TPL_TEST_RESET_SET(1) | + AD9154_SHORT_TPL_DAC_SEL_SET(i) | + AD9154_SHORT_TPL_SP_SEL_SET(0)) + # release reset stpl + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, + AD9154_SHORT_TPL_TEST_EN_SET(1) | + AD9154_SHORT_TPL_TEST_RESET_SET(0) | + AD9154_SHORT_TPL_DAC_SEL_SET(i) | + AD9154_SHORT_TPL_SP_SEL_SET(0)) + print("c{:d}: {:d}".format(i, self.ad9154.dac_read(AD9154_SHORT_TPL_TEST_3))) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 67bdc2ab8..56d9e97fe 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -543,6 +543,15 @@ class Phaser(_NIST_Ions): "converter{}".format(i)) # while at 5 GBps, take every second sample... FIXME self.comb += conv.eq(Cat(ch.o[::2])) + + # short transport layer test pattern + self.comb += [ + self.ad9154.jesd_core.transport.sink.converter0.eq(0x01230123), + self.ad9154.jesd_core.transport.sink.converter1.eq(0x45674567), + self.ad9154.jesd_core.transport.sink.converter2.eq(0x89ab89ab), + self.ad9154.jesd_core.transport.sink.converter3.eq(0xcdefcdef) + ] + self.comb += jesd_sync.eq(self.ad9154.jesd_sync) From bae5b73155159c61e47e5cd8056a9dd35a240e6f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 11 Oct 2016 19:50:19 +0200 Subject: [PATCH 031/157] phaser: comment out stpl test --- artiq/gateware/targets/kc705.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 56d9e97fe..520a0d5f4 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -544,13 +544,14 @@ class Phaser(_NIST_Ions): # while at 5 GBps, take every second sample... FIXME self.comb += conv.eq(Cat(ch.o[::2])) - # short transport layer test pattern - self.comb += [ - self.ad9154.jesd_core.transport.sink.converter0.eq(0x01230123), - self.ad9154.jesd_core.transport.sink.converter1.eq(0x45674567), - self.ad9154.jesd_core.transport.sink.converter2.eq(0x89ab89ab), - self.ad9154.jesd_core.transport.sink.converter3.eq(0xcdefcdef) - ] + if False: + # short transport layer test pattern + self.comb += [ + self.ad9154.jesd_core.transport.sink.converter0.eq(0x01230123), + self.ad9154.jesd_core.transport.sink.converter1.eq(0x45674567), + self.ad9154.jesd_core.transport.sink.converter2.eq(0x89ab89ab), + self.ad9154.jesd_core.transport.sink.converter3.eq(0xcdefcdef) + ] self.comb += jesd_sync.eq(self.ad9154.jesd_sync) From f515c11f269c01c18771fdf710d63ba053949578 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 11 Oct 2016 20:13:34 +0200 Subject: [PATCH 032/157] phaser: fix refclk period spec --- artiq/gateware/targets/kc705.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 520a0d5f4..82a459f87 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -402,7 +402,7 @@ class _PhaserCRG(Module, AutoCSR): self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) refclk_pads = platform.request("ad9154_refclk") - platform.add_period_constraint(refclk_pads.p, 5.) + platform.add_period_constraint(refclk_pads.p, 8.) self.refclk = Signal() self.clock_domains.cd_refclk = ClockDomain() self.specials += [ @@ -419,7 +419,7 @@ class _PhaserCRG(Module, AutoCSR): p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, p_REF_JITTER1=0.01, p_REF_JITTER2=0.01, - p_CLKIN1_PERIOD=5.0, p_CLKIN2_PERIOD=5.0, + p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, i_CLKIN1=rtio_internal_clk, i_CLKIN2=self.cd_refclk.clk, # Warning: CLKINSEL=0 means CLKIN2 is selected i_CLKINSEL=~self._clock_sel.storage, From 1117fe191bccd1e62a45efa3d85fa62461419fa3 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 12:03:29 +0200 Subject: [PATCH 033/157] phaser: support core stpl --- artiq/coredevice/ad9154.py | 9 +++++++++ artiq/gateware/targets/kc705.py | 9 --------- artiq/runtime/ad9154.c | 5 +++++ artiq/runtime/ad9154.h | 1 + artiq/runtime/ksupport.c | 1 + 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/ad9154.py b/artiq/coredevice/ad9154.py index 792c56652..64bb7fbf3 100644 --- a/artiq/coredevice/ad9154.py +++ b/artiq/coredevice/ad9154.py @@ -42,6 +42,11 @@ def ad9154_jesd_prbs(prbs: TInt32) -> TNone: raise NotImplementedError("syscall not simulated") +@syscall(flags={"nounwind", "nowrite"}) +def ad9154_jesd_stpl(prbs: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + + class AD9154: """AD9154-FMC-EBZ SPI support @@ -95,3 +100,7 @@ class AD9154: @kernel def jesd_prbs(self, prbs): ad9154_jesd_prbs(prbs) + + @kernel + def jesd_stpl(self, enable): + ad9154_jesd_stpl(enable) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 82a459f87..749cc6c20 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -544,15 +544,6 @@ class Phaser(_NIST_Ions): # while at 5 GBps, take every second sample... FIXME self.comb += conv.eq(Cat(ch.o[::2])) - if False: - # short transport layer test pattern - self.comb += [ - self.ad9154.jesd_core.transport.sink.converter0.eq(0x01230123), - self.ad9154.jesd_core.transport.sink.converter1.eq(0x45674567), - self.ad9154.jesd_core.transport.sink.converter2.eq(0x89ab89ab), - self.ad9154.jesd_core.transport.sink.converter3.eq(0xcdefcdef) - ] - self.comb += jesd_sync.eq(self.ad9154.jesd_sync) diff --git a/artiq/runtime/ad9154.c b/artiq/runtime/ad9154.c index 0711af8dc..31704bc3d 100644 --- a/artiq/runtime/ad9154.c +++ b/artiq/runtime/ad9154.c @@ -69,4 +69,9 @@ void ad9154_jesd_prbs(int p) ad9154_jesd_control_prbs_config_write(p); } +void ad9154_jesd_stpl(int en) +{ + ad9154_jesd_control_stpl_enable_write(en); +} + #endif /* CONFIG_AD9154_DAC_CS */ diff --git a/artiq/runtime/ad9154.h b/artiq/runtime/ad9154.h index 9ea6d0e5d..d6fa93d85 100644 --- a/artiq/runtime/ad9154.h +++ b/artiq/runtime/ad9154.h @@ -13,6 +13,7 @@ uint8_t ad9516_read(uint16_t addr); void ad9154_jesd_enable(int en); int ad9154_jesd_ready(void); void ad9154_jesd_prbs(int p); +void ad9154_jesd_stpl(int en); #endif #endif diff --git a/artiq/runtime/ksupport.c b/artiq/runtime/ksupport.c index fb3f6dff5..4bc8abec8 100644 --- a/artiq/runtime/ksupport.c +++ b/artiq/runtime/ksupport.c @@ -147,6 +147,7 @@ static const struct symbol runtime_exports[] = { {"ad9154_jesd_enable", &ad9154_jesd_enable}, {"ad9154_jesd_ready", &ad9154_jesd_ready}, {"ad9154_jesd_prbs", &ad9154_jesd_prbs}, + {"ad9154_jesd_stpl", &ad9154_jesd_stpl}, #endif /* end */ From 3b1d5d7eb63f260bd98c10b6c776dc8e59ffb466 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 12:19:08 +0200 Subject: [PATCH 034/157] phaser: verify flags in dac_setup --- artiq/examples/phaser/repository/dac_setup.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index 2a8297139..46577e95d 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -30,6 +30,7 @@ class DACSetup(EnvExperiment): self.setattr_device("core") self.setattr_device("led") self.setattr_device("ad9154") + self.setattr_device("sync") @kernel def run(self): @@ -38,10 +39,21 @@ class DACSetup(EnvExperiment): self.ad9154.jesd_prbs(0) self.ad9154.init() self.dac_setup() - self.busywait_us(200000) self.ad9154.jesd_enable(1) while not self.ad9154.jesd_ready(): pass + if self.ad9154.dac_read(AD9154_CODEGRPSYNCFLG) != 0x0f: + raise ValueError("no CODEGRPSYNCFLG") + self.core.break_realtime() + if not self.sync.sample_get_nonrt(): + pass #raise ValueError("SYNC still low") + if self.ad9154.dac_read(AD9154_FRAMESYNCFLG) != 0x0f: + raise ValueError("no FRAMESYNCFLG") + if self.ad9154.dac_read(AD9154_GOODCHKSUMFLG) != 0x0f: + raise ValueError("no GOODCHECKSUMFLG") + if self.ad9154.dac_read(AD9154_INITLANESYNCFLG) != 0x0f: + raise ValueError("no INITLANESYNCFLG") + self.monitor() @kernel def busywait_us(self, t): @@ -241,6 +253,9 @@ class DACSetup(EnvExperiment): # AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(1)) self.ad9154.dac_write(AD9154_SERDESPLL_ENABLE_CNTRL, AD9154_ENABLE_SERDESPLL_SET(1) | AD9154_RECAL_SERDESPLL_SET(0)) + while not AD9154_SERDES_PLL_LOCK_RB_GET(self.ad9154.dac_read(AD9154_PLL_STATUS)): + pass + self.ad9154.dac_write(AD9154_EQ_BIAS_REG, AD9154_EQ_BIAS_RESERVED_SET(0x22) | AD9154_EQ_POWER_MODE_SET(1)) @@ -279,8 +294,8 @@ class DACSetup(EnvExperiment): AD9154_LINK_EN_SET(0x1) | AD9154_LINK_PAGE_SET(0) | AD9154_LINK_MODE_SET(0) | AD9154_CHECKSUM_MODE_SET(0)) - self.busywait_us(1000) - + @kernel + def monitor(self): self.ad9154.dac_write(AD9154_IRQ_STATUS0, 0x00) self.ad9154.dac_write(AD9154_IRQ_STATUS1, 0x00) self.ad9154.dac_write(AD9154_IRQ_STATUS2, 0x00) From 5f737bef764c3423f5d14185a1f62b8682e76541 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 14:03:08 +0200 Subject: [PATCH 035/157] phaser: 500 MHz dacclock --- artiq/examples/phaser/repository/dac_setup.py | 8 ++++---- artiq/examples/phaser/startup_kernel.py | 12 ++++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index 46577e95d..de7d7a6da 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -20,9 +20,9 @@ ts = JESD204BTransportSettings( jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) jesd_checksum = jesd_settings.get_configuration_checksum() # external clk=2000MHz -# pclock=250MHz -# deviceclock_fpga=500MHz -# deviceclock_dac=2000MHz +# pclock=125MHz +# deviceclock_fpga=125MHz +# deviceclock_dac=500MHz class DACSetup(EnvExperiment): @@ -98,7 +98,7 @@ class DACSetup(EnvExperiment): 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, 1) # 2x 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_DATAPATH_CTRL, diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index 089d49d92..1d2890832 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -42,10 +42,14 @@ class StartupKernel(EnvExperiment): self.ad9154.clock_write(AD9516_OUT5, 2*AD9516_OUT5_POWER_DOWN) self.ad9154.clock_write(AD9516_OUT8, 1*AD9516_OUT8_POWER_DOWN) - # DAC deviceclk, clk/1 - self.ad9154.clock_write(AD9516_DIVIDER_0_2, AD9516_DIVIDER_0_DIRECT_TO_OUTPUT) - self.ad9154.clock_write(AD9516_OUT1, 0*AD9516_OUT1_POWER_DOWN | - 2*AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE) + # DAC deviceclk, dclk/1 + self.ad9154.clock_write(AD9516_DIVIDER_0_1, AD9516_DIVIDER_0_BYPASS) + self.ad9154.clock_write(AD9516_DIVIDER_0_2, + 0*AD9516_DIVIDER_0_DIRECT_TO_OUTPUT | + 0*AD9516_DIVIDER_0_DCCOFF) + self.ad9154.clock_write(AD9516_OUT1, + 0*AD9516_OUT1_POWER_DOWN | + 2*AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE) # FPGA deviceclk, dclk/4 self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_2) From 466d1e8304e2aa6e4c5687c454bc60e2483fb1b2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 14:22:21 +0200 Subject: [PATCH 036/157] phaser: update stpl --- .../phaser/repository/test_ad9154_stpl.py | 71 ++++++++++--------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/artiq/examples/phaser/repository/test_ad9154_stpl.py b/artiq/examples/phaser/repository/test_ad9154_stpl.py index bc5cc40c4..3dc3acda0 100644 --- a/artiq/examples/phaser/repository/test_ad9154_stpl.py +++ b/artiq/examples/phaser/repository/test_ad9154_stpl.py @@ -1,4 +1,4 @@ -import time +from jesd204b.transport import seed_to_data from artiq.coredevice.ad9154_reg import * from artiq.experiment import * @@ -10,36 +10,41 @@ class Test(EnvExperiment): self.setattr_device("ad9154") def run(self): - self.stpl() - - def stpl(self): + self.ad9154.jesd_stpl(0) # short transport layer test - for i, data in enumerate([0x0123, 0x4567, 0x89ab, 0xcdef]): - # select dac - self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, - AD9154_SHORT_TPL_TEST_EN_SET(0) | - AD9154_SHORT_TPL_TEST_RESET_SET(0) | - AD9154_SHORT_TPL_DAC_SEL_SET(i) | - AD9154_SHORT_TPL_SP_SEL_SET(0)) - # set expected value - self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_2, data & 0xff) - self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_1, (data & 0xff00) >> 8) - # enable stpl - self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, - AD9154_SHORT_TPL_TEST_EN_SET(1) | - AD9154_SHORT_TPL_TEST_RESET_SET(0) | - AD9154_SHORT_TPL_DAC_SEL_SET(i) | - AD9154_SHORT_TPL_SP_SEL_SET(0)) - # reset stpl - self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, - AD9154_SHORT_TPL_TEST_EN_SET(1) | - AD9154_SHORT_TPL_TEST_RESET_SET(1) | - AD9154_SHORT_TPL_DAC_SEL_SET(i) | - AD9154_SHORT_TPL_SP_SEL_SET(0)) - # release reset stpl - self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, - AD9154_SHORT_TPL_TEST_EN_SET(1) | - AD9154_SHORT_TPL_TEST_RESET_SET(0) | - AD9154_SHORT_TPL_DAC_SEL_SET(i) | - AD9154_SHORT_TPL_SP_SEL_SET(0)) - print("c{:d}: {:d}".format(i, self.ad9154.dac_read(AD9154_SHORT_TPL_TEST_3))) + for i in range(4): + data = seed_to_data(i << 8, True) + fail = self.stpl(i, data) + print("channel", i, "FAIL" if fail else "PASS") + self.ad9154.jesd_stpl(0) + + @kernel + def stpl(self, i, data): + # select dac + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, + AD9154_SHORT_TPL_TEST_EN_SET(0) | + AD9154_SHORT_TPL_TEST_RESET_SET(0) | + AD9154_SHORT_TPL_DAC_SEL_SET(i) | + AD9154_SHORT_TPL_SP_SEL_SET(0)) + # set expected value + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_2, data & 0xff) + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_1, (data & 0xff00) >> 8) + # enable stpl + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, + AD9154_SHORT_TPL_TEST_EN_SET(1) | + AD9154_SHORT_TPL_TEST_RESET_SET(0) | + AD9154_SHORT_TPL_DAC_SEL_SET(i) | + AD9154_SHORT_TPL_SP_SEL_SET(0)) + # reset stpl + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, + AD9154_SHORT_TPL_TEST_EN_SET(1) | + AD9154_SHORT_TPL_TEST_RESET_SET(1) | + AD9154_SHORT_TPL_DAC_SEL_SET(i) | + AD9154_SHORT_TPL_SP_SEL_SET(0)) + # release reset stpl + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, + AD9154_SHORT_TPL_TEST_EN_SET(1) | + AD9154_SHORT_TPL_TEST_RESET_SET(0) | + AD9154_SHORT_TPL_DAC_SEL_SET(i) | + AD9154_SHORT_TPL_SP_SEL_SET(0)) + return self.ad9154.dac_read(AD9154_SHORT_TPL_TEST_3) From 3f1d96b68d672c9c3ee5234390b705f3c7f013ce Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 14:22:33 +0200 Subject: [PATCH 037/157] phaser: tweak dac_setup --- artiq/examples/phaser/repository/dac_setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index de7d7a6da..f9f9b5721 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -37,11 +37,14 @@ class DACSetup(EnvExperiment): self.core.break_realtime() self.ad9154.jesd_enable(0) self.ad9154.jesd_prbs(0) + self.busywait_us(10000) self.ad9154.init() self.dac_setup() + self.busywait_us(10000) self.ad9154.jesd_enable(1) while not self.ad9154.jesd_ready(): pass + self.monitor() if self.ad9154.dac_read(AD9154_CODEGRPSYNCFLG) != 0x0f: raise ValueError("no CODEGRPSYNCFLG") self.core.break_realtime() @@ -53,7 +56,6 @@ class DACSetup(EnvExperiment): raise ValueError("no GOODCHECKSUMFLG") if self.ad9154.dac_read(AD9154_INITLANESYNCFLG) != 0x0f: raise ValueError("no INITLANESYNCFLG") - self.monitor() @kernel def busywait_us(self, t): From 4376ef561528b72c4e99e258f9edfd0a854491e6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 14:37:43 +0200 Subject: [PATCH 038/157] phaser: slow down spi a bit --- artiq/runtime/ad9154.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/runtime/ad9154.c b/artiq/runtime/ad9154.c index 31704bc3d..5bc5e49e2 100644 --- a/artiq/runtime/ad9154.c +++ b/artiq/runtime/ad9154.c @@ -16,8 +16,8 @@ void ad9154_init(void) ad9154_spi_clk_phase_write(0); ad9154_spi_lsb_first_write(0); ad9154_spi_half_duplex_write(0); - ad9154_spi_clk_div_write_write(11); - ad9154_spi_clk_div_read_write(11); + ad9154_spi_clk_div_write_write(16); + ad9154_spi_clk_div_read_write(16); ad9154_spi_xfer_len_write_write(24); ad9154_spi_xfer_len_read_write(0); ad9154_spi_cs_write(CONFIG_AD9154_DAC_CS); From 9644a3a362e2fdf2d2a9d6d605a99dfa4d8d68d7 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 15:00:53 +0200 Subject: [PATCH 039/157] ad9154: mix mode addr, digital gain must be on --- artiq/coredevice/ad9154_reg.py | 2 +- artiq/examples/phaser/repository/dac_setup.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/ad9154_reg.py b/artiq/coredevice/ad9154_reg.py index 1f51d7315..6993745c1 100644 --- a/artiq/coredevice/ad9154_reg.py +++ b/artiq/coredevice/ad9154_reg.py @@ -748,7 +748,7 @@ def AD9154_GROUPCOMP_BYPI_GET(x: TInt32) -> TInt32: return (x >> 1) & 0x1 -AD9154_MIX_MODE = 0x047 +AD9154_MIX_MODE = 0x04a AD9154_NCOALIGN_MODE = 0x050 # default: 0x00, access: R/W diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index f9f9b5721..fdb02501b 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -106,7 +106,7 @@ class DACSetup(EnvExperiment): self.ad9154.dac_write(AD9154_DATAPATH_CTRL, AD9154_I_TO_Q_SET(0) | AD9154_SEL_SIDEBAND_SET(0) | AD9154_MODULATION_TYPE_SET(0) | AD9154_PHASE_ADJ_ENABLE_SET(0) | - AD9154_DIG_GAIN_ENABLE_SET(0) | AD9154_INVSINC_ENABLE_SET(0)) + AD9154_DIG_GAIN_ENABLE_SET(1) | AD9154_INVSINC_ENABLE_SET(0)) self.ad9154.dac_write(AD9154_IDAC_DIG_GAIN0, 0x00) self.ad9154.dac_write(AD9154_IDAC_DIG_GAIN1, 0x8) self.ad9154.dac_write(AD9154_QDAC_DIG_GAIN0, 0x00) @@ -181,8 +181,8 @@ class DACSetup(EnvExperiment): self.ad9154.dac_write(AD9154_CTRLREG1, jesd_settings.transport.f) self.ad9154.dac_write(AD9154_CTRLREG2, AD9154_ILAS_MODE_SET(0) | AD9154_THRESHOLD_MASK_EN_SET(0)) - self.ad9154.dac_write(AD9154_KVAL, 1) # *4*K multiframes during ILAS - self.ad9154.dac_write(AD9154_LANEENABLE, 0x0f) + self.ad9154.dac_write(AD9154_KVAL, 1) # *4*K multiframes during ILAS + self.ad9154.dac_write(AD9154_LANEENABLE, 0x0f) # CGS _after_ this self.ad9154.dac_write(AD9154_TERM_BLK1_CTRLREG0, 1) self.ad9154.dac_write(AD9154_TERM_BLK2_CTRLREG0, 1) From 12b8598b84cfb36a294ef8cfcfbf97200b593577 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 12 Oct 2016 15:59:27 +0200 Subject: [PATCH 040/157] stpl: fix byte ordering --- artiq/examples/phaser/repository/test_ad9154_stpl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/phaser/repository/test_ad9154_stpl.py b/artiq/examples/phaser/repository/test_ad9154_stpl.py index 3dc3acda0..4e892177c 100644 --- a/artiq/examples/phaser/repository/test_ad9154_stpl.py +++ b/artiq/examples/phaser/repository/test_ad9154_stpl.py @@ -27,8 +27,8 @@ class Test(EnvExperiment): AD9154_SHORT_TPL_DAC_SEL_SET(i) | AD9154_SHORT_TPL_SP_SEL_SET(0)) # set expected value - self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_2, data & 0xff) - self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_1, (data & 0xff00) >> 8) + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_1, data & 0xff) + self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_2, (data & 0xff00) >> 8) # enable stpl self.ad9154.dac_write(AD9154_SHORT_TPL_TEST_0, AD9154_SHORT_TPL_TEST_EN_SET(1) | From 2d14864c6d0da745278e48c643cfe9c2b60ca57a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 15:07:08 +0200 Subject: [PATCH 041/157] Revert "phaser: 500 MHz dacclock" This reverts commit 5f737bef764c3423f5d14185a1f62b8682e76541. --- artiq/examples/phaser/repository/dac_setup.py | 8 ++++---- artiq/examples/phaser/startup_kernel.py | 12 ++++-------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index fdb02501b..f9cbaf90e 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -20,9 +20,9 @@ ts = JESD204BTransportSettings( jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) jesd_checksum = jesd_settings.get_configuration_checksum() # external clk=2000MHz -# pclock=125MHz -# deviceclock_fpga=125MHz -# deviceclock_dac=500MHz +# pclock=250MHz +# deviceclock_fpga=500MHz +# deviceclock_dac=2000MHz class DACSetup(EnvExperiment): @@ -100,7 +100,7 @@ class DACSetup(EnvExperiment): self.ad9154.dac_write(AD9154_SPI_PAGEINDX, 0x3) # A and B dual - self.ad9154.dac_write(AD9154_INTERP_MODE, 1) # 2x + self.ad9154.dac_write(AD9154_INTERP_MODE, 4) # 8x 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_DATAPATH_CTRL, diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index 1d2890832..089d49d92 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -42,14 +42,10 @@ class StartupKernel(EnvExperiment): self.ad9154.clock_write(AD9516_OUT5, 2*AD9516_OUT5_POWER_DOWN) self.ad9154.clock_write(AD9516_OUT8, 1*AD9516_OUT8_POWER_DOWN) - # DAC deviceclk, dclk/1 - self.ad9154.clock_write(AD9516_DIVIDER_0_1, AD9516_DIVIDER_0_BYPASS) - self.ad9154.clock_write(AD9516_DIVIDER_0_2, - 0*AD9516_DIVIDER_0_DIRECT_TO_OUTPUT | - 0*AD9516_DIVIDER_0_DCCOFF) - self.ad9154.clock_write(AD9516_OUT1, - 0*AD9516_OUT1_POWER_DOWN | - 2*AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE) + # DAC deviceclk, clk/1 + self.ad9154.clock_write(AD9516_DIVIDER_0_2, AD9516_DIVIDER_0_DIRECT_TO_OUTPUT) + self.ad9154.clock_write(AD9516_OUT1, 0*AD9516_OUT1_POWER_DOWN | + 2*AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE) # FPGA deviceclk, dclk/4 self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_2) From 0d1ed247e26b2d0edc49d848a7b46978fa0f0247 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 15:45:41 +0200 Subject: [PATCH 042/157] phaser: tweak sawg example --- artiq/examples/phaser/repository/sawg.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/artiq/examples/phaser/repository/sawg.py b/artiq/examples/phaser/repository/sawg.py index 3e276a240..e6749ce7d 100644 --- a/artiq/examples/phaser/repository/sawg.py +++ b/artiq/examples/phaser/repository/sawg.py @@ -14,19 +14,18 @@ class SAWGTest(EnvExperiment): @kernel def run(self): self.core.break_realtime() - delay(100*us) self.sawg0.set_amplitude(.1) - self.sawg1.set_amplitude(-.9) - self.sawg2.set_amplitude(.5) - self.sawg3.set_amplitude(.5) - self.sawg0.set_frequency(1*MHz) - self.sawg1.set_frequency(10*MHz) - self.sawg2.set_frequency(20*MHz) - self.sawg3.set_frequency(20*MHz) + self.sawg0.set_frequency(10*MHz) self.sawg0.set_phase(0.) + self.sawg1.set_amplitude(-.9) + self.sawg1.set_frequency(20*MHz) self.sawg1.set_phase(0.) + self.sawg2.set_amplitude(.5) + self.sawg2.set_frequency(30*MHz) self.sawg2.set_phase(0.) + self.sawg3.set_amplitude(.5) + self.sawg3.set_frequency(30*MHz) self.sawg3.set_phase(.5) for i in range(10): From 9880b1ebd03df14241d6117766033fc3b11afb34 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 16:00:46 +0200 Subject: [PATCH 043/157] phaser: update README --- README_PHASER.rst | 75 ++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/README_PHASER.rst b/README_PHASER.rst index 31558ab5a..9680ae1ee 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -3,30 +3,27 @@ ARTIQ Phaser This ARTIQ branch contains a proof-of-concept design of a GHz-datarate multichannel direct digital synthesizer (DDS) compatible with ARTIQ's RTIO channels. In later developments this proof-of-concept can be expanded to provide a two-tone output with spline modulation and multi-DAC synchronization. -Ultimately it will be the basis for the ARTIQ Sayma project. See https://github.com/m-labs/sayma and https://github.com/m-labs/artiq-hardware +Ultimately it will be the basis for the ARTIQ Sayma Smart Arbitrary Waveform Generator project. See https://github.com/m-labs/sayma and https://github.com/m-labs/artiq-hardware. -The hardware required is a KC705 with an AD9154-FMC-EBZ plugged into the HPC connector and a low-jitter 2 GHz reference clock. - -Features: +*Features*: * 4 channels * 500 MHz data rate per channel (KC705 limitation) * 4x interpolation to 2 GHz DAC sample rate -* Real-time control over amplitude, frequency, phase through ARTIQ RTIO - channels -* Full configurability of the AD9154 and AD9516 through SPI with ARTIQ kernel - support +* Real-time control over amplitude, frequency, phase of each channel through ARTIQ RTIO commands +* Full configurability of the AD9154 and AD9516 through SPI with ARTIQ kernel support * All SPI registers and register bits exposed as human readable names * Parametrized JESD204B core (also capable of operation with eight lanes) -* The code can be reconfigured, e.g. to support 2 channels at 1 GHz datarate or to support 4 channels at 300 MHz data rate, no interpolation, and using mix mode to stress the second and third Nyquist zones (150-300 MHz and 300-450 MHz). +* The code can be reconfigured. Possible example configurations are: support 2 channels at 1 GHz datarate, support 4 channels at 300 MHz data rate, no interpolation, and using mix mode to stress the second and third Nyquist zones (150-300 MHz and 300-450 MHz). + +The hardware required to use the ARTIQ phaser branch is a KC705 with an AD9154-FMC-EBZ plugged into the HPC connector and a low-noise 2 GHz reference clock. This work was supported by the Army Research Lab. -The additions and modifications to ARTIQ that were implemented for this project are: +The code that was developed for this project is located in several repositories: * In ARTIQ, the SAWG and Phaser code: https://github.com/m-labs/artiq/compare/phaser -* The CORDIC core has been reused from the PDQ2 gateware - https://github.com/m-labs/pdq2 +* The CORDIC core has been reused from the PDQ2 gateware https://github.com/m-labs/pdq2 * The Migen/MiSoC JESD204B core: https://github.com/m-labs/jesd204b @@ -34,20 +31,10 @@ Installation ------------ These installation instructions are a short form of those in the ARTIQ manual. -Please refer to the manual for more details: +Please refer to and follow the ARTIQ manual for more details: https://m-labs.hk/artiq/manual-release-2/index.html * Set up a new conda environment and activate it. -* Checkout the ARTIQ phaser branch and the JESD204B core: :: - - mkdir ~/src - cd ~/src - git clone --recursive -b phaser https://github.com/m-labs/artiq.git - git clone https://github.com/m-labs/jesd204b.git - cd jesd204b - python setup.py develop - cd ../artiq - * Install the standard ARTIQ runtime/install dependencies. See ``conda/artiq/meta.yaml`` for a list. They are all packaged as conda packages in ``m-labs/main``. @@ -60,17 +47,26 @@ https://m-labs.hk/artiq/manual-release-2/index.html - llvm-or1k - rust-core-or1k - cargo - - binutils-or1k-linux >=2.27 + - binutils-or1k-linux -* Vivado +* Install a recent version of Vivado (tested and developed with 2016.2). +* Checkout the ARTIQ phaser branch and the JESD204B core: :: -Follow the ARTIQ manual's chapter on installing. + mkdir ~/src + cd ~/src + git clone --recursive -b phaser https://github.com/m-labs/artiq.git + git clone https://github.com/m-labs/jesd204b.git + cd jesd204b + python setup.py develop + cd ../artiq + python setup.py develop Setup ----- -* Setup the KC705 (VADJ, jumpers, etc.) observing the ARTIQ manual. +* Setup the KC705 (jumpers, etc.) observing the ARTIQ manual. + VADJ does not need to be changed. * On the AD9154-FMC-EBZ put jumpers: - on XP1, between pin 5 and 6 (will keep the PIC in reset) @@ -80,17 +76,17 @@ Setup python -m artiq.gateware.targets.kc705 -H phaser --toolchain vivado -* Run the following OpenOCD commands to flash the ARTIQ transmitter design: :: +* Run the following OpenOCD command to flash the ARTIQ transmitter design: :: - init - jtagspi_init 0 bscan_spi_xc7k325t.bit - jtagspi_program misoc_phaser_kc705/gateware/top.bin 0x000000 - jtagspi_program misoc_phaser_kc705/software/bios/bios.bin 0xaf0000 - jtagspi_program misoc_phaser_kc705/software/runtime/runtime.fbi 0xb00000 - xc7_program xc7.tap - exit + openocd -f board/kc705.cfg -c "init; jtagspi_init 0 bscan_spi_xc7k325t.bit; jtagspi_program misoc_phaser_kc705/gateware/top.bin 0x000000; jtagspi_program misoc_phaser_kc705/software/bios/bios.bin 0xaf0000; jtagspi_program misoc_phaser_kc705/software/runtime/runtime.fbi 0xb00000; xc7_program xc7.tap; exit" - The proxy bitstream ``bscan_spi_xc7k325t.bit`` can be found at https://github.com/jordens/bscan_spi_bitstreams or in any ARTIQ conda package for the KC705. See the source code of ``artiq_flash.py`` from ARTIQ for more details. + The proxy bitstream ``bscan_spi_xc7k325t.bit`` can be found at https://github.com/jordens/bscan_spi_bitstreams or in any ARTIQ conda package for the KC705. + See the source code of ``artiq_flash.py`` from ARTIQ for more details. + + If you are using the OpenOCD Conda package: + + * locate the OpenOCD scripts directory with: ``python3 -c "import artiq.frontend.artiq_flash as af; print(af.scripts_path)"`` + * add ``-s `` to the OpenOCD command line. * Refer to the ARTIQ documentation to configure an IP address and other settings for the transmitter device. If the board was running stock ARTIQ before, the settings will be kept. @@ -103,12 +99,11 @@ Usage ----- * An example device database, several status and test scripts are provided in ``artiq/examples/phaser/``. -* After each boot, run the ``dac_setup.py`` experiment to establish and align the data link (``artiq_run repository/dac_setup.py``). -* run ``artiq_run repository/sawg.py`` for an example that sets up amplitudes, frequencies, - and phases on all four DDS channels. +* After each boot, run the ``dac_setup.py`` experiment to establish the JESD204B links (``artiq_run repository/dac_setup.py``). +* Run ``artiq_run repository/sawg.py`` for an example that sets up amplitudes, frequencies, and phases on all four DDS channels. * Implement your own experiments using the SAWG channels. * Verify clock stability between the 2 GHz reference clock and the DAC outputs. * Verify phase alignment between the DAC channels. * Changes to the AD9154 configuration can also be performed at runtime in experiments. - See the example ``startup_kernel.py``. + See the example ``dac_setup.py``. This can e.g. be used to enable and evaluate mix mode without having to change any other code (bitstream/bios/runtime/startup_kernel). From 9c8b21b3f4ede92934df52768e7c123c7654e654 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 16:13:34 +0200 Subject: [PATCH 044/157] phaser: let link settle a bit longer before starting --- artiq/examples/phaser/repository/dac_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index f9cbaf90e..45b7c17b9 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -40,7 +40,7 @@ class DACSetup(EnvExperiment): self.busywait_us(10000) self.ad9154.init() self.dac_setup() - self.busywait_us(10000) + self.busywait_us(200000) self.ad9154.jesd_enable(1) while not self.ad9154.jesd_ready(): pass From 81511feab80855b3257bbca660945b001dbc5330 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 12 Oct 2016 16:32:19 +0200 Subject: [PATCH 045/157] phaser: README: specify versions --- README_PHASER.rst | 12 ++++++------ conda/artiq-kc705-phaser/meta.yaml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README_PHASER.rst b/README_PHASER.rst index 9680ae1ee..a1527ef38 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -40,14 +40,14 @@ https://m-labs.hk/artiq/manual-release-2/index.html They are all packaged as conda packages in ``m-labs/main``. * Install the standard ARTIQ build dependencies. - They are all available as conda packages in m-labs/main at least for linux-64: + They are all available as conda packages in m-labs/main or m-labs/dev for linux-64: - - migen 0.4 - - misoc 0.3 - - llvm-or1k + - migen =0.4 + - misoc =0.4 + - llvm-or1k =3.8 - rust-core-or1k - cargo - - binutils-or1k-linux + - binutils-or1k-linux >=2.27 * Install a recent version of Vivado (tested and developed with 2016.2). * Checkout the ARTIQ phaser branch and the JESD204B core: :: @@ -76,7 +76,7 @@ Setup python -m artiq.gateware.targets.kc705 -H phaser --toolchain vivado -* Run the following OpenOCD command to flash the ARTIQ transmitter design: :: +* Run the following OpenOCD command to flash the ARTIQ phaser design: :: openocd -f board/kc705.cfg -c "init; jtagspi_init 0 bscan_spi_xc7k325t.bit; jtagspi_program misoc_phaser_kc705/gateware/top.bin 0x000000; jtagspi_program misoc_phaser_kc705/software/bios/bios.bin 0xaf0000; jtagspi_program misoc_phaser_kc705/software/runtime/runtime.fbi 0xb00000; xc7_program xc7.tap; exit" diff --git a/conda/artiq-kc705-phaser/meta.yaml b/conda/artiq-kc705-phaser/meta.yaml index 6c24032ba..febaf8b4f 100644 --- a/conda/artiq-kc705-phaser/meta.yaml +++ b/conda/artiq-kc705-phaser/meta.yaml @@ -13,7 +13,7 @@ build: requirements: build: - migen 0.4 - - misoc 0.3 + - misoc 0.4 - llvm-or1k - binutils-or1k-linux >=2.27 - rust-core-or1k From af0e8582a231beb2a09f716196eeb7bbda86a07e Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 13 Oct 2016 11:51:06 +0200 Subject: [PATCH 046/157] phaser: use new jesd clocking --- artiq/gateware/targets/kc705.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 749cc6c20..0684ebd29 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -466,10 +466,13 @@ class AD9154(Module, AutoCSR): rtio_freq = 125*1000*1000 jesd_qpll = GTXQuadPLL( rtio_crg.refclk, jesd_refclk_freq, jesd_linerate) - jesd_phys = [JESD204BPhyTX( - jesd_qpll, platform.request("ad9154_jesd", i), - rtio_freq, i) for i in range(4)] - self.submodules += jesd_qpll, jesd_phys + self.submodules += jesd_qpll + jesd_phys = [] + for i in range(4): + jesd_phy = [JESD204BPhyTX(jesd_qpll, + platform.request("ad9154_jesd", i), rtio_freq) + jesd_phys.append(jesd_phy) + setattr(self.submodules, "jesd_phy"+str(i), jesd_phy) for jesd_phy in jesd_phys: platform.add_period_constraint( jesd_phy.gtx.cd_tx.clk, From 78a41eec8fab7034899ee172224d58cd3620331f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Oct 2016 12:38:32 +0200 Subject: [PATCH 047/157] phaser: kc705: syntax --- artiq/gateware/targets/kc705.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 0684ebd29..a3d3853e5 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -469,8 +469,9 @@ class AD9154(Module, AutoCSR): self.submodules += jesd_qpll jesd_phys = [] for i in range(4): - jesd_phy = [JESD204BPhyTX(jesd_qpll, - platform.request("ad9154_jesd", i), rtio_freq) + jesd_phy = JESD204BPhyTX( + jesd_qpll, platform.request("ad9154_jesd", i), + rtio_freq) jesd_phys.append(jesd_phy) setattr(self.submodules, "jesd_phy"+str(i), jesd_phy) for jesd_phy in jesd_phys: From 01bfe54ddee34fbd29d205096dcac510c29918d3 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Oct 2016 14:09:29 +0200 Subject: [PATCH 048/157] phaser: actually enable stpl --- artiq/examples/phaser/repository/test_ad9154_stpl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/phaser/repository/test_ad9154_stpl.py b/artiq/examples/phaser/repository/test_ad9154_stpl.py index 4e892177c..d19e90d3b 100644 --- a/artiq/examples/phaser/repository/test_ad9154_stpl.py +++ b/artiq/examples/phaser/repository/test_ad9154_stpl.py @@ -10,7 +10,7 @@ class Test(EnvExperiment): self.setattr_device("ad9154") def run(self): - self.ad9154.jesd_stpl(0) + self.ad9154.jesd_stpl(1) # short transport layer test for i in range(4): data = seed_to_data(i << 8, True) From c8e45ae3f63281278d0e1ebbf2e030b36f82fc02 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Oct 2016 14:43:24 +0200 Subject: [PATCH 049/157] phaser: cleanup jesd phy instantiation a bit --- artiq/gateware/targets/kc705.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index a3d3853e5..70ae7928a 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -472,15 +472,14 @@ class AD9154(Module, AutoCSR): jesd_phy = JESD204BPhyTX( jesd_qpll, platform.request("ad9154_jesd", i), rtio_freq) - jesd_phys.append(jesd_phy) - setattr(self.submodules, "jesd_phy"+str(i), jesd_phy) - for jesd_phy in jesd_phys: platform.add_period_constraint( jesd_phy.gtx.cd_tx.clk, 40/jesd_linerate*1e9) platform.add_false_path_constraints( rtio_crg.cd_rtio.clk, jesd_phy.gtx.cd_tx.clk) + jesd_phys.append(jesd_phy) + setattr(self.submodules, "jesd_phy"+str(i), jesd_phy) self.submodules.jesd_core = JESD204BCoreTX( jesd_phys, jesd_settings, converter_data_width=32) self.comb += self.jesd_core.start.eq(jesd_sync) From 4c7c479c94a45acc4e29ce5a9bd6a668945cbc56 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Oct 2016 15:02:18 +0200 Subject: [PATCH 050/157] ad9154: add mirrored bits --- artiq/coredevice/ad9154_reg.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/ad9154_reg.py b/artiq/coredevice/ad9154_reg.py index 6993745c1..a7d414e96 100644 --- a/artiq/coredevice/ad9154_reg.py +++ b/artiq/coredevice/ad9154_reg.py @@ -39,22 +39,38 @@ def AD9154_SDOACTIVE_SET(x: TInt32) -> TInt32: def AD9154_SDOACTIVE_GET(x: TInt32) -> TInt32: return (x >> 3) & 0x1 -# default: 0x00, access: R +# default: 0x00, access: R/W +@portable +def AD9154_SDOACTIVE_M_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 4 + @portable def AD9154_SDOACTIVE_M_GET(x: TInt32) -> TInt32: return (x >> 4) & 0x1 -# default: 0x00, access: R +# default: 0x00, access: R/W +@portable +def AD9154_ADDRINC_M_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 5 + @portable def AD9154_ADDRINC_M_GET(x: TInt32) -> TInt32: return (x >> 5) & 0x1 -# default: 0x00, access: R +# default: 0x00, access: R/W +@portable +def AD9154_LSBFIRST_M_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 6 + @portable def AD9154_LSBFIRST_M_GET(x: TInt32) -> TInt32: return (x >> 6) & 0x1 -# default: 0x00, access: R +# default: 0x00, access: R/W +@portable +def AD9154_SOFTRESET_M_SET(x: TInt32) -> TInt32: + return (x & 0x1) << 7 + @portable def AD9154_SOFTRESET_M_GET(x: TInt32) -> TInt32: return (x >> 7) & 0x1 From b1137563b399f6cc0df951b764f2a4019e2c2ed6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Oct 2016 15:02:42 +0200 Subject: [PATCH 051/157] phaser: cleanup dac_setup --- artiq/examples/phaser/repository/dac_setup.py | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index 45b7c17b9..ced5971c8 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -34,28 +34,31 @@ class DACSetup(EnvExperiment): @kernel def run(self): - self.core.break_realtime() + self.core.reset() self.ad9154.jesd_enable(0) self.ad9154.jesd_prbs(0) + self.ad9154.jesd_stpl(0) self.busywait_us(10000) + self.ad9154.jesd_enable(1) self.ad9154.init() self.dac_setup() - self.busywait_us(200000) + self.ad9154.jesd_enable(0) + self.busywait_us(10000) self.ad9154.jesd_enable(1) + self.monitor() while not self.ad9154.jesd_ready(): pass - self.monitor() if self.ad9154.dac_read(AD9154_CODEGRPSYNCFLG) != 0x0f: - raise ValueError("no CODEGRPSYNCFLG") + raise ValueError("bad CODEGRPSYNCFLG") self.core.break_realtime() if not self.sync.sample_get_nonrt(): - pass #raise ValueError("SYNC still low") + raise ValueError("bad SYNC") if self.ad9154.dac_read(AD9154_FRAMESYNCFLG) != 0x0f: - raise ValueError("no FRAMESYNCFLG") + raise ValueError("bad FRAMESYNCFLG") if self.ad9154.dac_read(AD9154_GOODCHKSUMFLG) != 0x0f: - raise ValueError("no GOODCHECKSUMFLG") + raise ValueError("bad GOODCHECKSUMFLG") if self.ad9154.dac_read(AD9154_INITLANESYNCFLG) != 0x0f: - raise ValueError("no INITLANESYNCFLG") + raise ValueError("bad INITLANESYNCFLG") @kernel def busywait_us(self, t): @@ -66,11 +69,17 @@ class DACSetup(EnvExperiment): @kernel def dac_setup(self): # reset - self.ad9154.dac_write(AD9154_SPI_INTFCONFA, AD9154_SOFTRESET_SET(1) | - AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1)) + self.ad9154.dac_write(AD9154_SPI_INTFCONFA, + AD9154_SOFTRESET_M_SET(1) | AD9154_SOFTRESET_SET(1) | + AD9154_LSBFIRST_M_SET(0) | AD9154_LSBFIRST_SET(0) | + AD9154_ADDRINC_M_SET(0) | AD9154_ADDRINC_SET(0) | + AD9154_SDOACTIVE_M_SET(1) | AD9154_SDOACTIVE_SET(1)) self.busywait_us(100) self.ad9154.dac_write(AD9154_SPI_INTFCONFA, - AD9154_LSBFIRST_SET(0) | AD9154_SDOACTIVE_SET(1)) + AD9154_SOFTRESET_M_SET(0) | AD9154_SOFTRESET_SET(0) | + AD9154_LSBFIRST_M_SET(0) | AD9154_LSBFIRST_SET(0) | + AD9154_ADDRINC_M_SET(0) | AD9154_ADDRINC_SET(0) | + AD9154_SDOACTIVE_M_SET(1) | AD9154_SDOACTIVE_SET(1)) self.busywait_us(100) if ((self.ad9154.dac_read(AD9154_PRODIDH) << 8) | self.ad9154.dac_read(AD9154_PRODIDL) != 0x9154): @@ -281,8 +290,7 @@ class DACSetup(EnvExperiment): AD9154_SYNCCLRLAST_SET(0)) self.busywait_us(1000) # ensure at leas one sysref edge if not AD9154_SYNC_LOCK_GET(self.ad9154.dac_read(AD9154_SYNC_STATUS)): - pass - # raise ValueError("no sync lock") + raise ValueError("no sync lock") self.ad9154.dac_write(AD9154_XBAR_LN_0_1, AD9154_LOGICAL_LANE0_SRC_SET(7) | AD9154_LOGICAL_LANE1_SRC_SET(6)) self.ad9154.dac_write(AD9154_XBAR_LN_2_3, From 6a456bd7d4d443c48a64867c546c7273a10a42a4 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Oct 2016 15:17:38 +0200 Subject: [PATCH 052/157] phaser: feed correct sink (crucial) --- artiq/gateware/targets/kc705.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 70ae7928a..8f6fc5c08 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -542,7 +542,7 @@ class Phaser(_NIST_Ions): 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.transport.sink, + 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])) From 42c6658ffebf2050e65ebd0167733acea368e75e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Oct 2016 15:21:27 +0200 Subject: [PATCH 053/157] phaser: add some more blinking leds --- artiq/gateware/targets/kc705.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 8f6fc5c08..8623f6eba 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -483,8 +483,22 @@ class AD9154(Module, AutoCSR): self.submodules.jesd_core = JESD204BCoreTX( jesd_phys, jesd_settings, converter_data_width=32) self.comb += self.jesd_core.start.eq(jesd_sync) + self.comb += platform.request("user_led", 3).eq(jesd_sync) self.submodules.jesd_control = JESD204BCoreTXControl(self.jesd_core) + # blinking leds for transceiver reset status + for i in range(4): + led = platform.request("user_led", 4 + i) + counter = Signal(32) + sync = getattr(self.sync, "phy" + str(i)) + sync += \ + If(counter == 0, + led.eq(~led), + counter.eq(rtio_freq//2) + ).Else( + counter.eq(counter-1) + ) + class Phaser(_NIST_Ions): mem_map = { From 89150c9817c0006ecf68437688cf4e1889674078 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 13 Oct 2016 21:47:34 +0200 Subject: [PATCH 054/157] phaser: 10G line rate --- artiq/examples/phaser/repository/dac_setup.py | 6 +- artiq/examples/phaser/startup_kernel.py | 8 +- artiq/gateware/targets/kc705.py | 159 +++++++++--------- 3 files changed, 89 insertions(+), 84 deletions(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index ced5971c8..ab72829b9 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -109,7 +109,7 @@ class DACSetup(EnvExperiment): 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_DATA_FORMAT, AD9154_BINARY_FORMAT_SET(0)) # s16 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_CDR_OPERATING_MODE_REG_0, 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, 1) 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_REF_SEL_SET(0)) self.ad9154.dac_write(AD9154_LDO_FILTER_1, 0x62) # magic diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index 089d49d92..b611eef1a 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -47,17 +47,17 @@ class StartupKernel(EnvExperiment): self.ad9154.clock_write(AD9516_OUT1, 0*AD9516_OUT1_POWER_DOWN | 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_0, - (4//2-1)*AD9516_DIVIDER_0_HIGH_CYCLES | - (4//2-1)*AD9516_DIVIDER_0_LOW_CYCLES) + (2//2-1)*AD9516_DIVIDER_0_HIGH_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_OUT9, 1*AD9516_OUT9_LVDS_OUTPUT_CURRENT | 2*AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY | 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 | (32//2-1)*AD9516_DIVIDER_3_LOW_CYCLES_1) self.ad9154.clock_write(AD9516_DIVIDER_3_1, 0*AD9516_DIVIDER_3_PHASE_OFFSET_1 | diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 8623f6eba..759f3a229 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -398,19 +398,10 @@ class _PhaserCRG(Module, AutoCSR): self._clock_sel = CSRStorage() self._pll_reset = CSRStorage(reset=1) self._pll_locked = CSRStatus() + self.refclk = Signal() self.clock_domains.cd_rtio = ClockDomain() 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() rtio_clk = Signal() rtiox4_clk = Signal() @@ -419,13 +410,13 @@ class _PhaserCRG(Module, AutoCSR): p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, p_REF_JITTER1=0.01, p_REF_JITTER2=0.01, - p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, - i_CLKIN1=rtio_internal_clk, i_CLKIN2=self.cd_refclk.clk, + p_CLKIN1_PERIOD=4.0, p_CLKIN2_PERIOD=4.0, + i_CLKIN1=0, i_CLKIN2=self.refclk, # 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, + p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=2, i_CLKFBIN=self.cd_rtio.clk, 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=rtiox4_clk, o_O=self.cd_rtiox4.clk), - 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): - def __init__(self, platform, rtio_crg): - 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 - +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) - jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) - jesd_linerate = 5e9 - jesd_refclk_freq = 125e6 - rtio_freq = 125*1000*1000 - jesd_qpll = GTXQuadPLL( - rtio_crg.refclk, jesd_refclk_freq, jesd_linerate) - self.submodules += jesd_qpll - jesd_phys = [] + settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) + linerate = 10e9 + refclk_freq = 250e6 + fabric_freq = 250*1000*1000 + + sync_pads = platform.request("ad9154_sync") + self.jsync = Signal() + 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): - jesd_phy = JESD204BPhyTX( - jesd_qpll, platform.request("ad9154_jesd", i), - rtio_freq) - platform.add_period_constraint( - jesd_phy.gtx.cd_tx.clk, - 40/jesd_linerate*1e9) + phy = JESD204BPhyTX( + qpll, platform.request("ad9154_jesd", i), fabric_freq) + platform.add_period_constraint(phy.gtx.cd_tx.clk, 40*1e9/linerate) platform.add_false_path_constraints( - rtio_crg.cd_rtio.clk, - jesd_phy.gtx.cd_tx.clk) - jesd_phys.append(jesd_phy) - setattr(self.submodules, "jesd_phy"+str(i), jesd_phy) - self.submodules.jesd_core = JESD204BCoreTX( - jesd_phys, jesd_settings, converter_data_width=32) - self.comb += self.jesd_core.start.eq(jesd_sync) - self.comb += platform.request("user_led", 3).eq(jesd_sync) - self.submodules.jesd_control = JESD204BCoreTXControl(self.jesd_core) + self.cd_jesd.clk, + phy.gtx.cd_tx.clk) + phys.append(phy) + to_jesd = ClockDomainsRenamer("jesd") + self.submodules.core = to_jesd(JESD204BCoreTX(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): led = platform.request("user_led", 4 + i) - counter = Signal(32) - sync = getattr(self.sync, "phy" + str(i)) + counter = Signal(max=fabric_freq//2 + 1) + sync = getattr(self.sync, "phy{}_tx".format(i)) sync += \ If(counter == 0, led.eq(~led), - counter.eq(rtio_freq//2) + counter.eq(fabric_freq//2) ).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): mem_map = { "ad9154": 0x50000000, @@ -512,7 +528,10 @@ class Phaser(_NIST_Ions): platform = self.platform 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 = [] @@ -525,13 +544,13 @@ class Phaser(_NIST_Ions): 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)) - jesd_sync = Signal() - phy = ttl_simple.Input(jesd_sync) + 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)) @@ -539,29 +558,15 @@ class Phaser(_NIST_Ions): self.config["RTIO_REGULAR_TTL_COUNT"] = 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) - for sawg in sawgs + 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.add_rtio(rtio_channels, _PhaserCRG(platform, self.crg.cd_sys.clk)) - to_rtio = ClockDomainsRenamer({"sys": "rtio"}) - 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) + self.comb += self.rtio_crg.refclk.eq(self.ad9154.jesd.refclk) def main(): From 342d6d756e57811ef3f0e05d7ca14d2d4bebb6df Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 00:59:53 +0200 Subject: [PATCH 055/157] phaser: bypass gtx phalign --- artiq/gateware/targets/kc705.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 759f3a229..449cdabe1 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -466,6 +466,7 @@ class AD9154JESD(Module, AutoCSR): phy = JESD204BPhyTX( qpll, platform.request("ad9154_jesd", i), fabric_freq) platform.add_period_constraint(phy.gtx.cd_tx.clk, 40*1e9/linerate) + self.comb += phy.gtx.gtx_init.bypass_phalign.eq(1) # TODO platform.add_false_path_constraints( self.cd_jesd.clk, phy.gtx.cd_tx.clk) From 808874a5231b295f91296d81d82fe9fa1290df5c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 01:57:48 +0200 Subject: [PATCH 056/157] phaser: drive cd_jesd with BUFG --- artiq/gateware/targets/kc705.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 449cdabe1..1d6446d7c 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -455,7 +455,7 @@ class AD9154JESD(Module, AutoCSR): 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), + Instance("BUFG", i_I=self.refclk, o_O=self.cd_jesd.clk), AsyncResetSynchronizer(self.cd_jesd, ResetSignal("rio_phy")), ] From 2b5a69a80ceee6088fd3ebcf0bed56346a09fe2b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 02:18:15 +0200 Subject: [PATCH 057/157] phaser: rm idle_kernel --- artiq/examples/phaser/idle_kernel.py | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 artiq/examples/phaser/idle_kernel.py diff --git a/artiq/examples/phaser/idle_kernel.py b/artiq/examples/phaser/idle_kernel.py deleted file mode 100644 index 704787fb1..000000000 --- a/artiq/examples/phaser/idle_kernel.py +++ /dev/null @@ -1,21 +0,0 @@ -from artiq.experiment import * - - -class IdleKernel(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("led") - - @kernel - def run(self): - start_time = now_mu() + seconds_to_mu(500*ms) - while self.core.get_rtio_counter_mu() < start_time: - pass - self.core.reset() - while True: - self.led.pulse(250*ms) - delay(125*ms) - self.led.pulse(125*ms) - delay(125*ms) - self.led.pulse(125*ms) - delay(250*ms) From b9de621557031f04fd300bc2cb521db6b22279cf Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 02:18:58 +0200 Subject: [PATCH 058/157] phaser: fix comment --- artiq/examples/phaser/repository/dac_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index ab72829b9..974a8c9aa 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -21,7 +21,7 @@ jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) jesd_checksum = jesd_settings.get_configuration_checksum() # external clk=2000MHz # pclock=250MHz -# deviceclock_fpga=500MHz +# deviceclock_fpga=250MHz # deviceclock_dac=2000MHz From 3c9c42c779d494610875815b2310ace0bba4af94 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 02:26:19 +0200 Subject: [PATCH 059/157] phaser: drive rtio from jesd-bufg --- artiq/gateware/targets/kc705.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 1d6446d7c..b593869e1 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -567,7 +567,7 @@ class Phaser(_NIST_Ions): rtio_channels.append(rtio.LogChannel()) self.add_rtio(rtio_channels, _PhaserCRG(platform, self.crg.cd_sys.clk)) - self.comb += self.rtio_crg.refclk.eq(self.ad9154.jesd.refclk) + self.comb += self.rtio_crg.refclk.eq(self.ad9154.jesd.cd_jesd.clk) def main(): From e400f8d672d23e621eea14986281315278544a50 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 09:54:56 +0200 Subject: [PATCH 060/157] phaser: add two more registers before jesd --- artiq/gateware/targets/kc705.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index b593869e1..6d7dedc01 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -511,10 +511,11 @@ class AD9154(Module, AutoCSR): x = Signal() y = Signal() - self.sync.jesd += x.eq(~x) + z = Signal() + self.sync.jesd += x.eq(~x), z.eq(x == y) 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:]))) + self.sync.jesd += conv.eq(Mux(z, Cat(ch.o[:2]), Cat(ch.o[2:]))) class Phaser(_NIST_Ions): From 4ea3dea217ed002168a249379d89dc50a4042792 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 10:22:03 +0200 Subject: [PATCH 061/157] phaser: broad spectrum antibiotics with xilinx false paths --- artiq/gateware/targets/kc705.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 6d7dedc01..e77f8db80 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -467,9 +467,8 @@ class AD9154JESD(Module, AutoCSR): qpll, platform.request("ad9154_jesd", i), fabric_freq) platform.add_period_constraint(phy.gtx.cd_tx.clk, 40*1e9/linerate) self.comb += phy.gtx.gtx_init.bypass_phalign.eq(1) # TODO - platform.add_false_path_constraints( - self.cd_jesd.clk, - phy.gtx.cd_tx.clk) + for clk in self.cd_jesd.clk, refclk_pads.p, self.refclk: + platform.add_false_path_constraints(clk, phy.gtx.cd_tx.clk) phys.append(phy) to_jesd = ClockDomainsRenamer("jesd") self.submodules.core = to_jesd(JESD204BCoreTX(phys, settings, From b41b9de905ef5b92961859534e26c459e0687d5c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 10:46:33 +0200 Subject: [PATCH 062/157] phaser: tag jesd as clock net --- artiq/gateware/targets/kc705.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index e77f8db80..3a7151365 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -458,6 +458,7 @@ class AD9154JESD(Module, AutoCSR): Instance("BUFG", i_I=self.refclk, o_O=self.cd_jesd.clk), AsyncResetSynchronizer(self.cd_jesd, ResetSignal("rio_phy")), ] + platform.add_period_constraint(self.cd_jesd.clk, 1e9/refclk_freq) qpll = GTXQuadPLL(self.refclk, refclk_freq, linerate) self.submodules += qpll @@ -467,8 +468,8 @@ class AD9154JESD(Module, AutoCSR): qpll, platform.request("ad9154_jesd", i), fabric_freq) platform.add_period_constraint(phy.gtx.cd_tx.clk, 40*1e9/linerate) self.comb += phy.gtx.gtx_init.bypass_phalign.eq(1) # TODO - for clk in self.cd_jesd.clk, refclk_pads.p, self.refclk: - platform.add_false_path_constraints(clk, phy.gtx.cd_tx.clk) + platform.add_false_path_constraints(self.cd_jesd.clk, + phy.gtx.cd_tx.clk) phys.append(phy) to_jesd = ClockDomainsRenamer("jesd") self.submodules.core = to_jesd(JESD204BCoreTX(phys, settings, From 9b43f09c1dcb0aa3556a83908f8339776e6434b5 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 11:56:10 +0200 Subject: [PATCH 063/157] phaser: cleanup prbs --- artiq/examples/phaser/repository/dac_setup.py | 2 +- .../phaser/repository/test_ad9154_prbs.py | 29 +++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index 974a8c9aa..3a1693ecb 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -62,7 +62,7 @@ class DACSetup(EnvExperiment): @kernel def busywait_us(self, t): - t = now_mu() + seconds_to_mu(t*us) + t = self.core.get_rtio_counter_mu() + seconds_to_mu(t*us) while self.core.get_rtio_counter_mu() < t: pass diff --git a/artiq/examples/phaser/repository/test_ad9154_prbs.py b/artiq/examples/phaser/repository/test_ad9154_prbs.py index 337da468f..c5aedcb2c 100644 --- a/artiq/examples/phaser/repository/test_ad9154_prbs.py +++ b/artiq/examples/phaser/repository/test_ad9154_prbs.py @@ -1,5 +1,3 @@ -import time - from artiq.coredevice.ad9154_reg import * from artiq.experiment import * @@ -9,14 +7,25 @@ class Test(EnvExperiment): self.setattr_device("core") self.setattr_device("ad9154") + @kernel def run(self): - for i in range(3): # prbs7, prbs15, prbs31 - self.prbs(i, 100) + for e in range(2): + for i in range(3): # prbs7, prbs15, prbs31 + self.prbs(i, 10, e) + + @kernel + def busywait_us(self, t): + t = self.core.get_rtio_counter_mu() + seconds_to_mu(t*us) + while self.core.get_rtio_counter_mu() < t: + pass def p(self, f, *a): - print(f % a) + print(f.format(*a)) - def prbs(self, p, t, inject_errors=0): + @kernel + def prbs(self, p, t, inject_errors): + self.p("---\nprbs sequence {}, threshold {}, inject_errors {}:", + p, t, inject_errors) self.ad9154.jesd_prbs((1 << p) | (inject_errors << 3)) self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, @@ -35,15 +44,17 @@ class Test(EnvExperiment): self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, AD9154_PHY_PRBS_PAT_SEL_SET(p) | AD9154_PHY_TEST_START_SET(1)) - time.sleep(.5) + self.busywait_us(1000000) self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, AD9154_PHY_PRBS_PAT_SEL_SET(p)) - self.p("prbs status: 0x%02x", self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_STATUS)) + self.p("prbs status: {:#04x}", self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_STATUS)) for i in range(8): self.ad9154.dac_write(AD9154_PHY_PRBS_TEST_CTRL, AD9154_PHY_SRC_ERR_CNT_SET(i)) - self.p("prbs errors[%d]: 0x%08x", i, + self.p("prbs errors[{}]: {:#08x}", i, self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_ERRCNT_LOBITS) | (self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_ERRCNT_MIDBITS) << 8) | (self.ad9154.dac_read(AD9154_PHY_PRBS_TEST_ERRCNT_HIBITS) << 16)) + + self.ad9154.jesd_prbs(0) From d16068dd9b6ff53d21961e9aeeadbc81ab44947b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 12:11:39 +0200 Subject: [PATCH 064/157] sawg: absolute phase updates --- artiq/gateware/dsp/sawg.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index f39b3603a..6d6fdb241 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -37,8 +37,10 @@ class DDSFast(Module): If(self.f.stb, eqh(q.i.f, self.f.f) ), + q.i.clr.eq(0), If(self.p.stb, - eqh(q.i.p, self.p.p) + eqh(q.i.p, self.p.p), + q.i.clr.eq(1) ), q.i.stb.eq(self.f.stb | self.p.stb), ] @@ -47,7 +49,6 @@ class DDSFast(Module): self.f.ack.eq(1), self.p.ack.eq(1), q.o.ack.eq(1), - q.i.clr.eq(0), ] c = [] From 4b4fd32e3d756e555c593ba33a621c6602b32e5c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 13:21:42 +0200 Subject: [PATCH 065/157] phaser: add another sawg demo --- artiq/examples/phaser/repository/demo.py | 50 ++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 artiq/examples/phaser/repository/demo.py diff --git a/artiq/examples/phaser/repository/demo.py b/artiq/examples/phaser/repository/demo.py new file mode 100644 index 000000000..ba67b96a4 --- /dev/null +++ b/artiq/examples/phaser/repository/demo.py @@ -0,0 +1,50 @@ +from artiq.experiment import * + + +class SAWGTest(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("led") + self.setattr_device("ttl_sma") + + self.setattr_device("sawg0") + self.setattr_device("sawg1") + self.setattr_device("sawg2") + self.setattr_device("sawg3") + + @kernel + def run(self): + self.core.break_realtime() + self.ttl_sma.output() + + while True: + self.sawg0.set_amplitude(0.) + self.sawg0.set_frequency(0*MHz) + self.sawg1.set_amplitude(0.) + self.sawg1.set_frequency(0*MHz) + delay(20*ms) + + self.sawg0.set_amplitude(.4) + self.sawg0.set_frequency(10*MHz) + self.sawg0.set_phase(0.) + self.sawg1.set_amplitude(.4) + self.sawg1.set_frequency(10*MHz) + self.sawg1.set_phase(0.) + self.ttl_sma.pulse(200*ns) + self.sawg1.set_amplitude(.1) + delay(200*ns) + self.sawg1.set_amplitude(-.4) + self.ttl_sma.pulse(200*ns) + self.sawg1.set_amplitude(.4) + delay(200*ns) + self.sawg1.set_phase(.25) + self.ttl_sma.pulse(200*ns) + self.sawg1.set_phase(.5) + delay(200*ns) + self.sawg0.set_phase(.5) + self.ttl_sma.pulse(200*ns) + self.sawg1.set_frequency(30*MHz) + delay(200*ns) + self.sawg1.set_frequency(10*MHz) + self.sawg1.set_phase(0.) + self.ttl_sma.pulse(200*ns) From 4968de053cf0269311aabb8069ae8908b82ca5ee Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 13:21:54 +0200 Subject: [PATCH 066/157] phaser: update README --- README_PHASER.rst | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README_PHASER.rst b/README_PHASER.rst index a1527ef38..617519ea8 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -92,18 +92,28 @@ Setup If the board was running stock ARTIQ before, the settings will be kept. * A 2 GHz of roughly 10 dBm (0.2 to 3.4 V peak-to-peak into 50 Ohm) must be connected to the AD9154-FMC-EBZ J1. The external RTIO clock, DAC deviceclock, FPGA deviceclock, and SYSREF are derived from this signal. +* An example device database, several status and test scripts are provided in ``artiq/examples/phaser/``. :: + + cd artiq/examples/phaser + +* Edit ``device_db.pyon`` to match the hostname or IP address of the core device. * The ``startup_clock`` needs to be set to internal (``i``) for bootstrapping the clock distribution tree. * Compile and flash the startup kernel in ``artiq/examples/phaser/startup_kernel.py``. +* Erase any possible idle kernels. +* Use ``ping`` and ``flterm`` to verify that the core device starts up and boots correctly. Usage ----- -* An example device database, several status and test scripts are provided in ``artiq/examples/phaser/``. * After each boot, run the ``dac_setup.py`` experiment to establish the JESD204B links (``artiq_run repository/dac_setup.py``). +* Run ``artiq_run repository/ad9154_test_status.py`` to retrieve and print several status registers from the AD9154 DAC. +* Run ``artiq_run repository/ad9154_test_prbs.py`` to test the JESD204B PHY layer for bit errors. Reboot the core device afterwards. +* Run ``artiq_run repository/ad9154_test_stpl.py`` to executes a JESD204B short transport layer test. * Run ``artiq_run repository/sawg.py`` for an example that sets up amplitudes, frequencies, and phases on all four DDS channels. +* Run ``artiq_run repository/demo.py`` for an example that exercises several different use cases of synchronized phase, amplitude, and frequency updates. + for an example that exercises several different use cases of synchronized phase, amplitude, and frequency updates. * Implement your own experiments using the SAWG channels. * Verify clock stability between the 2 GHz reference clock and the DAC outputs. -* Verify phase alignment between the DAC channels. * Changes to the AD9154 configuration can also be performed at runtime in experiments. See the example ``dac_setup.py``. This can e.g. be used to enable and evaluate mix mode without having to change any other code (bitstream/bios/runtime/startup_kernel). From 9ba6be879605dd40e56d6041ffd53ce76cd103b8 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 14 Oct 2016 13:23:14 +0200 Subject: [PATCH 067/157] phaser: speed up ad9154_test_status --- artiq/examples/phaser/repository/test_ad9154_status.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/examples/phaser/repository/test_ad9154_status.py b/artiq/examples/phaser/repository/test_ad9154_status.py index 6c401155c..0f047a8c7 100644 --- a/artiq/examples/phaser/repository/test_ad9154_status.py +++ b/artiq/examples/phaser/repository/test_ad9154_status.py @@ -7,6 +7,7 @@ class Test(EnvExperiment): self.setattr_device("core") self.setattr_device("ad9154") + @kernel def run(self): self.print_status() self.print_temp() @@ -14,6 +15,7 @@ class Test(EnvExperiment): def p(self, f, *a): print(f % a) + @kernel def print_temp(self): self.ad9154.dac_write(AD9154_DIE_TEMP_CTRL0, AD9154_AUXADC_RESERVED_SET(0x10) | AD9154_AUXADC_ENABLE_SET(1)) @@ -23,6 +25,7 @@ class Test(EnvExperiment): self.ad9154.dac_write(AD9154_DIE_TEMP_CTRL0, AD9154_AUXADC_RESERVED_SET(0x10) | AD9154_AUXADC_ENABLE_SET(0)) + @kernel def print_status(self): x = self.ad9154.dac_read(AD9154_IRQ_STATUS0) self.p("LANEFIFOERR: %d, SERPLLLOCK: %d, SERPLLLOST: %d, " From 0259c800153491744af625238558ba22fa2df662 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 14 Oct 2016 19:06:43 +0200 Subject: [PATCH 068/157] phaser/kc705: remove transceiver initialization workaround --- artiq/gateware/targets/kc705.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 3a7151365..f3abcd3ec 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -93,7 +93,7 @@ class _RTIOCRG(Module, AutoCSR): # 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. +# 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")), @@ -316,7 +316,7 @@ class NIST_CLOCK(_NIST_Ions): class NIST_QC2(_NIST_Ions): """ NIST QC2 hardware, as used in Quantum I and Quantum II, with new backplane - and 24 DDS channels. Two backplanes are used. + and 24 DDS channels. Two backplanes are used. """ def __init__(self, cpu_type="or1k", **kwargs): _NIST_Ions.__init__(self, cpu_type, **kwargs) @@ -333,19 +333,19 @@ class NIST_QC2(_NIST_Ions): 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): + for i in range(2): phy = ttl_simple.ClockGen( platform.request("clkout", i)) self.submodules += phy - clock_generators.append(rtio.Channel.from_phy(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)) @@ -467,7 +467,6 @@ class AD9154JESD(Module, AutoCSR): phy = JESD204BPhyTX( qpll, platform.request("ad9154_jesd", i), fabric_freq) platform.add_period_constraint(phy.gtx.cd_tx.clk, 40*1e9/linerate) - self.comb += phy.gtx.gtx_init.bypass_phalign.eq(1) # TODO platform.add_false_path_constraints(self.cd_jesd.clk, phy.gtx.cd_tx.clk) phys.append(phy) From 6a683c712b8a44e6416f415f8a005b35b1bd4705 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 16 Oct 2016 16:01:23 +0200 Subject: [PATCH 069/157] phaser: work around for unreliable transciever init --- artiq/examples/phaser/repository/dac_setup.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index 3a1693ecb..ed9a2da76 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -34,6 +34,19 @@ class DACSetup(EnvExperiment): @kernel def run(self): + # TODO; remove when + # https://github.com/m-labs/jesd204b/issues/6 + # is resolved + for i in range(99): + try: + self.cfg() + return + except: + pass + self.cfg() + + @kernel + def cfg(self): self.core.reset() self.ad9154.jesd_enable(0) self.ad9154.jesd_prbs(0) @@ -48,6 +61,7 @@ class DACSetup(EnvExperiment): self.monitor() while not self.ad9154.jesd_ready(): pass + self.busywait_us(10000) if self.ad9154.dac_read(AD9154_CODEGRPSYNCFLG) != 0x0f: raise ValueError("bad CODEGRPSYNCFLG") self.core.break_realtime() From b6002529cffd37962bf8b34c1638c86d10b3763b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 17 Oct 2016 14:06:35 +0800 Subject: [PATCH 070/157] gateware/spi: fix import --- artiq/gateware/spi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/spi.py b/artiq/gateware/spi.py index 17ab523ad..23e52915f 100644 --- a/artiq/gateware/spi.py +++ b/artiq/gateware/spi.py @@ -2,7 +2,7 @@ from itertools import product from migen import * from misoc.interconnect import wishbone -from misoc.cores.spi.core import SPIMachine +from misoc.cores.spi import SPIMachine class SPIMaster(Module): From b2327cf8081c335fd89b743835dbbebd3d010bb4 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 17 Oct 2016 22:00:16 +0200 Subject: [PATCH 071/157] sawg: core is kernel_invariant --- artiq/coredevice/sawg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 2732b1e03..2a078143d 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -10,7 +10,7 @@ class SAWG: Frequency and Phase are then assumed to be successive channels. """ kernel_invariants = {"amplitude_scale", "frequency_scale", "phase_scale", - "channel_base"} + "channel_base", "core"} def __init__(self, dmgr, channel_base, parallelism=4, core_device="core"): self.core = dmgr.get(core_device) From 78700a67bc0cbdbf0b7209d4be8e76f726005401 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 17 Oct 2016 22:13:17 +0200 Subject: [PATCH 072/157] sawg: fast-math --- artiq/coredevice/sawg.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 2a078143d..f6f90f973 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -32,13 +32,13 @@ class SAWG: """ rtio_output(now_mu(), self.channel_base, 0, amplitude) - @kernel + @kernel(flags=["fast-math"]) def set_amplitude(self, amplitude: TFloat): """Set DDS amplitude. :param amplitude: DDS amplitude relative to full-scale. """ - self.set_amplitude_mu(int(amplitude*self.amplitude_scale)) + self.set_amplitude_mu(int(round(amplitude*self.amplitude_scale))) @kernel def set_frequency_mu(self, frequency: TInt32): @@ -48,13 +48,13 @@ class SAWG: """ rtio_output(now_mu(), self.channel_base + 1, 0, frequency) - @kernel + @kernel(flags=["fast-math"]) def set_frequency(self, frequency: TFloat): """Set DDS frequency. :param frequency: DDS frequency in Hz. """ - self.set_frequency_mu(int(frequency*self.frequency_scale)) + self.set_frequency_mu(int(round(frequency*self.frequency_scale))) @kernel def set_phase_mu(self, phase: TInt32): @@ -64,10 +64,10 @@ class SAWG: """ rtio_output(now_mu(), self.channel_base + 2, 0, phase) - @kernel + @kernel(flags=["fast-math"]) def set_phase(self, phase: TFloat): """Set DDS phase. :param phase: DDS phase relative in turns. """ - self.set_phase_mu(int(phase*self.phase_scale)) + self.set_phase_mu(int(round(phase*self.phase_scale))) From 54f05b6fc1ec4b9570f791cc700d8d81dc6838b2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 18 Oct 2016 10:06:51 +0200 Subject: [PATCH 073/157] ksupport: kernel_run lookup with dyld (closes #590) adapt to misoc change --- artiq/runtime/ksupport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/runtime/ksupport.c b/artiq/runtime/ksupport.c index 4bc8abec8..8236166d2 100644 --- a/artiq/runtime/ksupport.c +++ b/artiq/runtime/ksupport.c @@ -409,7 +409,7 @@ int main(void) } if(request->run_kernel) { - void (*kernel_run)() = request->library_info->init; + void (*kernel_run)() = dyld_lookup("__modinit__", request->library_info); void *typeinfo = dyld_lookup("typeinfo", request->library_info); mailbox_send_and_wait(&load_reply); From bf942fc22858370dd378343aa5b36e6ec8fb39e6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 18 Oct 2016 11:37:27 +0200 Subject: [PATCH 074/157] ksupport: adapt to dyld_load() --- artiq/runtime/ksupport.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/runtime/ksupport.c b/artiq/runtime/ksupport.c index 8236166d2..bd99ced68 100644 --- a/artiq/runtime/ksupport.c +++ b/artiq/runtime/ksupport.c @@ -333,7 +333,8 @@ int dl_iterate_phdr (int (*callback)(struct dl_phdr_info *, size_t, void *), voi return retval; } -static Elf32_Addr resolve_runtime_export(const char *name) +static Elf32_Addr resolve_runtime_export(void *resolve_data, + const char *name) { const struct symbol *sym = runtime_exports; while(sym->name) { @@ -397,7 +398,7 @@ int main(void) if(request->library != NULL) { if(!dyld_load(request->library, KERNELCPU_PAYLOAD_ADDRESS, - resolve_runtime_export, request->library_info, + resolve_runtime_export, NULL, request->library_info, &load_reply.error)) { mailbox_send(&load_reply); while(1); From 062aca2a6bfddaf4980bbcdc360c31eeee6daa05 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 19 Oct 2016 14:44:54 +0200 Subject: [PATCH 075/157] conda/phaser: build-depend on jesd204b --- conda/artiq-kc705-phaser/meta.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/conda/artiq-kc705-phaser/meta.yaml b/conda/artiq-kc705-phaser/meta.yaml index febaf8b4f..a30476c50 100644 --- a/conda/artiq-kc705-phaser/meta.yaml +++ b/conda/artiq-kc705-phaser/meta.yaml @@ -14,6 +14,7 @@ requirements: build: - migen 0.4 - misoc 0.4 + - jesd204b 0.1 - llvm-or1k - binutils-or1k-linux >=2.27 - rust-core-or1k From d2f776b0d0cfe4c31bd4d94b411b7e2921b92ffc Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 24 Oct 2016 17:38:01 +0200 Subject: [PATCH 076/157] phaser: add more tools --- artiq/gateware/dsp/spline.py | 46 ++++++++++++++++++++++++++++++ artiq/gateware/dsp/tools.py | 44 ++++++++++++++++++++++++++++ artiq/test/gateware/test_spline.py | 31 ++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 artiq/gateware/dsp/spline.py create mode 100644 artiq/test/gateware/test_spline.py diff --git a/artiq/gateware/dsp/spline.py b/artiq/gateware/dsp/spline.py new file mode 100644 index 000000000..0061653dc --- /dev/null +++ b/artiq/gateware/dsp/spline.py @@ -0,0 +1,46 @@ +from migen import * +from misoc.interconnect.stream import Endpoint + + +class Spline(Module): + def __init__(self, order, width, step=1, time_width=None): + if not (step == 1 or order <= 2): + raise ValueError("For non-linear splines, " + "`step` needs to be one.") + layout = [("a{}".format(i), (width, True)) for i in range(order)] + self.i = Endpoint(layout) + self.o = Endpoint(layout) + self.latency = 1 + + ### + + o = self.o.payload.flatten() + + self.comb += self.i.ack.eq(~self.o.stb | self.o.ack) + self.sync += [ + If(self.o.ack, + self.o.stb.eq(0), + ), + If(self.i.ack, + self.o.stb.eq(1), + [o[i].eq(o[i] + (o[i + 1] << log2_int(step))) + for i in range(order - 1)], + If(self.i.stb, + self.o.payload.eq(self.i.payload), + ), + ), + ] + + def tri(self, time_width): + layout = [(name, (length - i*time_width, signed)) + for i, (name, (length, signed), dir) in + enumerate(self.i.payload.layout[::-1])] + layout.reverse() + i = Endpoint(layout) + self.comb += [ + self.i.stb.eq(i.stb), + i.ack.eq(self.i.ack), + [i0[-len(i1):].eq(i1) for i0, i1 in + zip(self.i.payload.flatten(), i.payload.flatten())] + ] + return i diff --git a/artiq/gateware/dsp/tools.py b/artiq/gateware/dsp/tools.py index 947745242..1e220ecce 100644 --- a/artiq/gateware/dsp/tools.py +++ b/artiq/gateware/dsp/tools.py @@ -1,3 +1,6 @@ +from operator import add +from functools import reduce + from migen import * @@ -27,10 +30,51 @@ def xfer(dut, **kw): ep.remove(e) +class Delay(Module): + def __init__(self, i, delay, o=None): + if isinstance(i, (int, tuple)): + z = [Signal(i) for j in range(delay + 1)] + elif isinstance(i, list): + z = [Record(i) for j in range(delay + 1)] + elif isinstance(i, Record): + z = [Record(i.layout) for j in range(delay + 1)] + else: + z = [Signal.like(i) for j in range(delay + 1)] + self.i = z[0] + self.o = z[-1] + if not isinstance(i, (int, list, tuple)): + self.comb += self.i.eq(i) + if o is not None: + self.comb += o.eq(self.o) + self.latency = delay + self.sync += [z[j + 1].eq(z[j]) for j in range(delay)] + + def eqh(a, b): return a[-len(b):].eq(b[-len(a):]) +class SatAddMixin: + def sat_add(self, a): + a = list(a) + # assert all(value_bits_sign(ai)[1] for ai in a) + n = max(len(ai) for ai in a) + o = log2_int(len(a), need_pow2=False) + s = Signal((n + o, True)) + s0 = Signal((n, True)) + z = Signal((1, True)) + self.comb += [ + s.eq(reduce(add, a, z)), + s0[-1].eq(s[-1]), + If(s[-o-1:] == Replicate(s[-1], o + 1), + s0[:-1].eq(s[:n-1]), + ).Else( + s0[:-1].eq(Replicate(~s[-1], n - 1)), + ) + ] + return s0 + + def szip(*iters): active = {it: None for it in iters} while active: diff --git a/artiq/test/gateware/test_spline.py b/artiq/test/gateware/test_spline.py new file mode 100644 index 000000000..6fca4f555 --- /dev/null +++ b/artiq/test/gateware/test_spline.py @@ -0,0 +1,31 @@ +import numpy as np + +from migen import * +from migen.fhdl.verilog import convert + +from artiq.gateware.dsp.spline import Spline +from artiq.gateware.dsp.tools import xfer + + +def _test_gen_spline(dut, o): + yield dut.o.ack.eq(1) + yield from xfer(dut, i=dict(a0=0, a1=1, a2=2)) + for i in range(20): + yield + o.append((yield dut.o.a0)) + + +def _test_spline(): + dut = Spline(order=3, width=16, step=1) + + if False: + print(convert(dut)) + else: + o = [] + run_simulation(dut, _test_gen_spline(dut, o), vcd_name="spline.vcd") + o = np.array(o) + print(o) + + +if __name__ == "__main__": + _test_spline() From e981b235486f4ef91f6952a4b0dd94c4fb47ef1e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 24 Oct 2016 19:33:23 +0200 Subject: [PATCH 077/157] phaser: use misoc cordic --- artiq/gateware/dsp/cordic.py | 358 ----------------------------------- artiq/gateware/dsp/sawg.py | 2 +- 2 files changed, 1 insertion(+), 359 deletions(-) delete mode 100644 artiq/gateware/dsp/cordic.py diff --git a/artiq/gateware/dsp/cordic.py b/artiq/gateware/dsp/cordic.py deleted file mode 100644 index f09ca5031..000000000 --- a/artiq/gateware/dsp/cordic.py +++ /dev/null @@ -1,358 +0,0 @@ -# Copyright 2014-2015 Robert Jordens -# -# This file is part of redpid. -# -# redpid is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# redpid is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with redpid. If not, see . - -from math import atan, atanh, log, sqrt, pi - -from migen import * - - -class TwoQuadrantCordic(Module): - """Coordinate rotation digital computer - - Trigonometric, and arithmetic functions implemented using - additions/subtractions and shifts. - - http://eprints.soton.ac.uk/267873/1/tcas1_cordic_review.pdf - - http://www.andraka.com/files/crdcsrvy.pdf - - http://zatto.free.fr/manual/Volder_CORDIC.pdf - - The way the CORDIC is executed is controlled by `eval_mode`. - If `"iterative"` the stages are iteratively evaluated, one per clock - cycle. This mode uses the least amount of registers, but has the - lowest throughput and highest latency. If `"pipelined"` all stages - are executed in every clock cycle but separated by registers. This - mode has full throughput but uses many registers and has large - latency. If `"combinatorial"`, there are no registers, throughput is - maximal and latency is zero. `"pipelined"` and `"combinatorial"` use - the same number of shifters and adders. - - The type of trigonometric/arithmetic function is determined by - `cordic_mode` and `func_mode`. :math:`g` is the gain of the CORDIC. - - * rotate-circular: rotate the vector `(xi, yi)` by an angle `zi`. - Used to calculate trigonometric functions, `sin(), cos(), - tan() = sin()/cos()`, or to perform polar-to-cartesian coordinate - transformation: - - .. math:: - x_o = g \\cos(z_i) x_i - g \\sin(z_i) y_i - - y_o = g \\sin(z_i) x_i + g \\cos(z_i) y_i - - * vector-circular: determine length and angle of the vector - `(xi, yi)`. Used to calculate `arctan(), sqrt()` or - to perform cartesian-to-polar transformation: - - .. math:: - x_o = g\\sqrt{x_i^2 + y_i^2} - - z_o = z_i + \\tan^{-1}(y_i/x_i) - - * rotate-hyperbolic: hyperbolic functions of `zi`. Used to - calculate hyperbolic functions, `sinh, cosh, tanh = cosh/sinh, - exp = cosh + sinh`: - - .. math:: - x_o = g \\cosh(z_i) x_i + g \\sinh(z_i) y_i - - y_o = g \\sinh(z_i) x_i + g \\cosh(z_i) z_i - - * vector-hyperbolic: natural logarithm `ln(), arctanh()`, and - `sqrt()`. Use `x_i = a + b` and `y_i = a - b` to obtain `2* - sqrt(a*b)` and `ln(a/b)/2`: - - .. math:: - x_o = g\\sqrt{x_i^2 - y_i^2} - - z_o = z_i + \\tanh^{-1}(y_i/x_i) - - * rotate-linear: multiply and accumulate (not a very good - multiplier implementation): - - .. math:: - y_o = g(y_i + x_i z_i) - - * vector-linear: divide and accumulate: - - .. math:: - z_o = g(z_i + y_i/x_i) - - Parameters - ---------- - width : int - Bit width of the input and output signals. Defaults to 16. Input - and output signals are signed. - widthz : int - Bit with of `zi` and `zo`. Defaults to the `width`. - stages : int or None - Number of CORDIC incremental rotation stages. Defaults to - `width + min(1, guard)`. - guard : int or None - Add guard bits to the intermediate signals. If `None`, - defaults to `guard = log2(width)` which guarantees accuracy - to `width` bits. - eval_mode : str, {"iterative", "pipelined", "combinatorial"} - cordic_mode : str, {"rotate", "vector"} - func_mode : str, {"circular", "linear", "hyperbolic"} - Evaluation and arithmetic mode. See above. - - Attributes - ---------- - xi, yi, zi : Signal(width), in - Input values, signed. - xo, yo, zo : Signal(width), out - Output values, signed. - new_out : Signal(1), out - Asserted if output values are freshly updated in the current - cycle. - new_in : Signal(1), out - Asserted if new input values are being read in the next cycle. - zmax : float - `zi` and `zo` normalization factor. Floating point `zmax` - corresponds to `1<<(widthz - 1)`. `x` and `y` are scaled such - that floating point `1` corresponds to `1<<(width - 1)`. - gain : float - Cumulative, intrinsic gain and scaling factor. In circular mode - `sqrt(xi**2 + yi**2)` should be no larger than `2**(width - 1)/gain` - to prevent overflow. Additionally, in hyperbolic and linear mode, - the operation itself can cause overflow. - interval : int - Output interval in clock cycles. Inverse throughput. - latency : int - Input-to-output latency. The result corresponding to the inputs - appears at the outputs `latency` cycles later. - - Notes - ----- - - Each stage `i` in the CORDIC performs the following operation: - - .. math:: - x_{i+1} = x_i - m d_i y_i r^{-s_{m,i}}, - - y_{i+1} = y_i + d_i x_i r^{-s_{m,i}}, - - z_{i+1} = z_i - d_i a_{m,i}, - - where: - - * :math:`d_i`: clockwise or counterclockwise, determined by - `sign(z_i)` in rotate mode or `sign(-y_i)` in vector mode. - - * :math:`r`: radix of the number system (2) - - * :math:`m`: 1: circular, 0: linear, -1: hyperbolic - - * :math:`s_{m,i}`: non decreasing integer shift sequence - - * :math:`a_{m,i}`: elemetary rotation angle: :math:`a_{m,i} = - \\tan^{-1}(\\sqrt{m} s_{m,i})/\\sqrt{m}`. - """ - def __init__(self, width=16, widthz=None, stages=None, guard=0, - eval_mode="iterative", cordic_mode="rotate", - func_mode="circular"): - # validate parameters - assert eval_mode in ("combinatorial", "pipelined", "iterative") - assert cordic_mode in ("rotate", "vector") - assert func_mode in ("circular", "linear", "hyperbolic") - self.cordic_mode = cordic_mode - self.func_mode = func_mode - if guard is None: - # guard bits to guarantee "width" accuracy - guard = int(log(width)/log(2)) - if widthz is None: - widthz = width - if stages is None: - stages = width + min(1, guard) # cuts error below LSB - - # input output interface - self.xi = Signal((width, True)) - self.yi = Signal((width, True)) - self.zi = Signal((widthz, True)) - self.xo = Signal((width, True)) - self.yo = Signal((width, True)) - self.zo = Signal((widthz, True)) - self.new_in = Signal() - self.new_out = Signal() - - ### - - a, s, self.zmax, self.gain = self._constants(stages, widthz + guard) - stages = len(a) # may have increased due to repetitions - - if eval_mode == "iterative": - num_sig = 3 - self.interval = stages + 1 - self.latency = stages + 2 - else: - num_sig = stages + 1 - self.interval = 1 - if eval_mode == "pipelined": - self.latency = stages - else: # combinatorial - self.latency = 0 - - # inter-stage signals - x = [Signal((width + guard, True)) for i in range(num_sig)] - y = [Signal((width + guard, True)) for i in range(num_sig)] - z = [Signal((widthz + guard, True)) for i in range(num_sig)] - - # hook up inputs and outputs to the first and last inter-stage - # signals - self.comb += [ - x[0].eq(self.xi << guard), - y[0].eq(self.yi << guard), - z[0].eq(self.zi << guard), - self.xo.eq(x[-1] >> guard), - self.yo.eq(y[-1] >> guard), - self.zo.eq(z[-1] >> guard), - ] - - if eval_mode == "iterative": - # We afford one additional iteration for in/out. - i = Signal(max=stages + 1) - self.comb += [ - self.new_in.eq(i == stages), - self.new_out.eq(i == 1), - ] - ai = Signal((widthz + guard, True)) - self.sync += ai.eq(Array(a)[i]) - if range(stages) == s: - si = i - 1 # shortcut if no stage repetitions - else: - si = Signal(max=stages + 1) - self.sync += si.eq(Array(s)[i]) - xi, yi, zi = x[1], y[1], z[1] - self.sync += [ - self._stage(xi, yi, zi, xi, yi, zi, si, ai), - i.eq(i + 1), - If(i == stages, - i.eq(0), - ), - If(i == 0, - x[2].eq(xi), y[2].eq(yi), z[2].eq(zi), - xi.eq(x[0]), yi.eq(y[0]), zi.eq(z[0]), - ) - ] - else: - self.comb += [ - self.new_out.eq(1), - self.new_in.eq(1), - ] - for i, si in enumerate(s): - stmt = self._stage(x[i], y[i], z[i], - x[i + 1], y[i + 1], z[i + 1], - si, a[i]) - if eval_mode == "pipelined": - self.sync += stmt - else: # combinatorial - self.comb += stmt - - def _constants(self, stages, bits): - if self.func_mode == "circular": - s = range(stages) - a = [atan(2**-i) for i in s] - g = [sqrt(1 + 2**(-2*i)) for i in s] - #zmax = sum(a) - # use pi anyway as the input z can cause overflow - # and we need the range for quadrant mapping - zmax = pi - elif self.func_mode == "linear": - s = range(stages) - a = [2**-i for i in s] - g = [1 for i in s] - #zmax = sum(a) - # use 2 anyway as this simplifies a and scaling - zmax = 2. - else: # hyperbolic - s = [] - # need to repeat some stages: - j = 4 - for i in range(stages): - if i == j: - s.append(j) - j = 3*j + 1 - s.append(i + 1) - a = [atanh(2**-i) for i in s] - g = [sqrt(1 - 2**(-2*i)) for i in s] - zmax = sum(a)*2 - # round here helps the width=2**i - 1 case but hurts the - # important width=2**i case - cast = int - if log(bits)/log(2) % 1: - cast = round - a = [cast(ai*2**(bits - 1)/zmax) for ai in a] - gain = 1. - for gi in g: - gain *= gi - return a, s, zmax, gain - - def _stage(self, xi, yi, zi, xo, yo, zo, i, ai): - dir = Signal() - if self.cordic_mode == "rotate": - self.comb += dir.eq(zi < 0) - else: # vector - self.comb += dir.eq(yi >= 0) - dx = yi >> i - dy = xi >> i - dz = ai - if self.func_mode == "linear": - dx = 0 - elif self.func_mode == "hyperbolic": - dx = -dx - stmt = [ - xo.eq(xi + Mux(dir, dx, -dx)), - yo.eq(yi + Mux(dir, -dy, dy)), - zo.eq(zi + Mux(dir, dz, -dz)) - ] - return stmt - - -class Cordic(TwoQuadrantCordic): - """Four-quadrant CORDIC - - Same as :class:`TwoQuadrantCordic` but with support and convergence - for `abs(zi) > pi/2 in circular rotate mode or `xi < 0` in circular - vector mode. - """ - def __init__(self, **kwargs): - TwoQuadrantCordic.__init__(self, **kwargs) - if self.func_mode != "circular": - return # no need to remap quadrants - - cxi, cyi, czi = self.xi, self.yi, self.zi - self.xi = xi = Signal.like(cxi) - self.yi = yi = Signal.like(cyi) - self.zi = zi = Signal.like(czi) - - ### - - q = Signal() - if self.cordic_mode == "rotate": - self.comb += q.eq(zi[-2] ^ zi[-1]) - else: # vector - self.comb += q.eq(xi < 0) - self.comb += [ - If(q, - Cat(cxi, cyi, czi).eq( - Cat(-xi, -yi, zi + (1 << len(zi) - 1))) - ).Else( - Cat(cxi, cyi, czi).eq(Cat(xi, yi, zi)) - ) - ] diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 6d6fdb241..c9b5fa176 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -1,7 +1,7 @@ from migen import * from misoc.interconnect.stream import Endpoint -from .cordic import Cordic +from misoc.cores.cordic import Cordic from .accu import PhasedAccu from .tools import eqh From ea0c304a0c91155d615031642df3798055c5a852 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 27 Oct 2016 01:00:42 +0200 Subject: [PATCH 078/157] phaser2: wip --- artiq/gateware/dsp/sawg.py | 290 +++++++++++++++++++++++++++++++- artiq/gateware/rtio/phy/sawg.py | 14 +- 2 files changed, 296 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index c9b5fa176..8b61ded8f 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -2,8 +2,9 @@ from migen import * from misoc.interconnect.stream import Endpoint from misoc.cores.cordic import Cordic -from .accu import PhasedAccu -from .tools import eqh +from .accu import PhasedAccu, Accu +from .tools import eqh, Delay +from .spline import Spline class DDSFast(Module): @@ -66,3 +67,288 @@ class DDSFast(Module): ] self.latency += c[0].latency self.gain = c[0].gain + + +class DDSFast(Module): + def __init__(self, width, t_width=None, + a_width=None, p_width=None, f_width=None, + a_order=4, p_order=1, f_order=2, parallelism=8): + if t_width is None: + t_width = width + if a_width is None: + a_width = width + (a_order - 1)*t_width + if p_width is None: + p_width = width + (p_order - 1)*t_width + if f_width is None: + f_width = width + (f_order + 1)*t_width + a = Spline(order=a_order, width=a_width) + p = Spline(order=p_order, width=p_width) + f = Spline(order=f_order, width=f_width) + self.submodules += a, p, f + + self.a = a.tri(t_width) + self.f = f.tri(t_width) + self.p = p.tri(t_width) + self.i = [self.a, self.f, self.p] + self.o = [[Signal((width, True)) for i in range(2)] + for i in range(parallelism)] + self.parallelism = parallelism + self.latency = 0 # will be accumulated + + ### + + self.latency += p.latency + q = PhasedAccu(f_width, parallelism) + self.submodules += q + self.latency += q.latency + da = [Signal((width, True)) for i in range(q.latency)] + + self.sync += [ + If(q.i.stb & q.i.ack, + eqh(da[0], a.o.a0), + [da[i + 1].eq(da[i]) for i in range(len(da) - 1)], + ), + If(p.o.stb & p.o.ack, + q.i.clr.eq(0), + ), + If(p.i.stb & p.i.ack, + q.i.clr.eq(self.clr), + ), + ] + self.comb += [ + a.o.ack.eq(self.ce), + p.o.ack.eq(self.ce), + f.o.ack.eq(self.ce), + q.i.stb.eq(self.ce), + eqh(q.i.p, p.o.a0), + q.i.f.eq(f.o.a0), + q.o.ack.eq(1), + ] + + c = [] + for i in range(parallelism): + ci = Cordic(width=width, widthz=p_width, + guard=None, eval_mode="pipelined") + self.submodules += ci + c.append(ci) + qoi = getattr(q.o, "z{}".format(i)) + self.comb += [ + ci.xi.eq(da[-1]), + ci.yi.eq(0), + eqh(ci.zi, qoi), + eqh(self.o[i][0], ci.xo), + eqh(self.o[i][1], ci.yo), + ] + self.latency += c[0].latency + self.gain = c[0].gain + + +class DDSSlow(Module): + def __init__(self, width, t_width, a_width, p_width, f_width, + a_order=4, p_order=1, f_order=2): + a = Spline(order=a_order, width=a_width) + p = Spline(order=p_order, width=p_width) + f = Spline(order=f_order, width=f_width) + self.submodules += a, p, f + + self.a = a.tri(t_width) + self.f = f.tri(t_width) + self.p = p.tri(t_width) + self.i = [self.a, self.f, self.p] + self.i_names = "a f p".split() + self.o = [Signal((width, True)) for i in range(2)] + self.ce = Signal() + self.clr = Signal() + self.latency = 0 # will be accumulated + + ### + + self.latency += p.latency + q = Accu(f_width) + self.latency += q.latency + da = CEInserter()(Delay)(width, q.latency) + c = Cordic(width=width, widthz=p_width, + guard=None, eval_mode="pipelined") + self.latency += c.latency + self.gain = c.gain + self.submodules += q, da, c + + self.sync += [ + If(p.o.stb & p.o.ack, + q.i.clr.eq(0), + ), + If(p.i.stb & p.i.ack, + q.i.clr.eq(self.clr), + ), + ] + self.comb += [ + da.ce.eq(q.i.stb & q.i.ack), + a.o.ack.eq(self.ce), + p.o.ack.eq(self.ce), + f.o.ack.eq(self.ce), + q.i.stb.eq(self.ce), + eqh(da.i, a.o.a0), + eqh(q.i.p, p.o.a0), + q.i.f.eq(f.o.a0), + q.o.ack.eq(1), + c.xi.eq(da.o), + c.yi.eq(0), + eqh(c.zi, q.o.z), + eqh(self.o[0], c.xo), + eqh(self.o[1], c.yo), + ] + + +class DDS(Module): + def __init__(self, width, t_width=None, + a_width=None, p_width=None, f_width=None, + a_order=4, p_order=1, f_order=2, parallelism=8): + if t_width is None: + t_width = width + if a_width is None: + a_width = width + (a_order - 1)*t_width + if p_width is None: + p_width = width + (p_order - 1)*t_width + if f_width is None: + f_width = width + (f_order + 1)*t_width + self.b = [DDSSlow(width, t_width, a_width, p_width, f_width, a_order, + p_order, f_order) for i in range(2)] + p = Spline(order=1, width=p_width) + f = Spline(order=1, width=f_width) + self.submodules += self.b, p, f + + self.f0 = f.tri(t_width) + self.p0 = p.tri(t_width) + self.i = [self.f0, self.p0] + self.i_names = "f0 p0".split() + for i, bi in enumerate(self.b): + self.i += bi.i + for ii in bi.i_names: + self.i_names.append("{}{}".format(ii, i + 1)) + for j in "afp": + setattr(self, "{}{}".format(j, i + 1), getattr(bi, j)) + self.o = [[Signal((width, True)) for i in range(2)] + for i in range(parallelism)] + self.ce = Signal() + self.clr = Signal() + self.parallelism = parallelism + self.latency = 0 # will be accumulated + + ### + + self.latency += self.b[0].latency # TODO: f0/p0, q.latency delta + q = PhasedAccu(f_width, parallelism) + self.submodules += q + + self.sync += [ + If(p.o.stb & p.o.ack, + q.i.clr.eq(0), + ), + If(p.i.stb & p.i.ack, + q.i.clr.eq(self.clr), + ), + ] + self.comb += [ + [bi.ce.eq(self.ce) for bi in self.b], + [bi.clr.eq(self.clr) for bi in self.b], + p.o.ack.eq(self.ce), + f.o.ack.eq(self.ce), + q.i.stb.eq(self.ce), + eqh(q.i.p, p.o.a0), + eqh(q.i.f, f.o.a0), + q.o.ack.eq(1), + ] + x = self.sat_add(bi.o[0] for bi in self.b) + y = self.sat_add(bi.o[1] for bi in self.b) + + c = [] + for i in range(parallelism): + ci = Cordic(width=width, widthz=p_width, + guard=None, eval_mode="pipelined") + self.submodules += ci + c.append(ci) + qoi = getattr(q.o, "z{}".format(i)) + self.comb += [ + ci.xi.eq(x), + ci.yi.eq(y), + eqh(ci.zi, qoi), + eqh(self.o[i][0], ci.xo), + eqh(self.o[i][1], ci.yo), + ] + self.latency += c[0].latency + self.gain = self.b[0].gain * c[0].gain + + +class Config(Module): + def __init__(self): + self.cfg = Record([("tap", 5), ("clr", 1), ("iq", 2)]) + self.i = Endpoint(self.cfg.layout) + self.ce = Signal() + + ### + + n = Signal(1 << len(self.i.tap)) + tap = Signal.like(self.i.tap) + clk = Signal() + clk0 = Signal() + + self.comb += [ + self.i.ack.eq(1), + clk.eq(Array(n)[tap]), + ] + self.sync += [ + clk0.eq(clk), + self.ce.eq(0), + If(clk0 ^ clk, + self.ce.eq(1), + ), + n.eq(n + 1), + If(self.i.stb, + n.eq(0), + self.cfg.eq(self.i.payload), + ), + ] + + +class Channel(Module): + def __init__(self, width=16, t_width=None, u_order=4, **kwargs): + if t_width is None: + t_width = width + du = Spline(width=width + (u_order - 1)*t_width, order=u_order) + da = DDS(width, t_width, **kwargs) + cfg = Config() + self.submodules += du, da, cfg + self.i = [cfg.i, du.tri(t_width)] + da.i + self.i_names = "cfg u".split() + da.i_names + self.q_i = [Signal((width, True)) for i in range(da.parallelism)] + self.q_o = [ai[1] for ai in da.o] + self.o = [Signal((width, True)) for i in range(da.parallelism)] + self.width = width + self.parallelism = da.parallelism + self.latency = da.latency + 1 + self.cordic_gain = da.gain + + ### + + # delay du to match da + ddu = Delay((width, True), da.latency - du.latency) + self.submodules += ddu + self.comb += [ + ddu.i.eq(du.o.a0[-width:]), + da.clr.eq(cfg.cfg.clr), + da.ce.eq(cfg.ce), + du.o.ack.eq(cfg.ce), + ] + # wire up outputs and q_{i,o} exchange + for oi, ai, qi in zip(self.o, da.o, self.q_i): + self.sync += [ + oi.eq(self.sat_add([ + ddu.o + + # du.o.a0[-width:], + Mux(cfg.cfg.iq[0], ai[0], 0), + Mux(cfg.cfg.iq[1], qi, 0)])), + ] + + def connect_q(self, buddy): + for i, qi in enumerate(self.q_i): + self.comb += qi.eq(buddy.q_o[i]) diff --git a/artiq/gateware/rtio/phy/sawg.py b/artiq/gateware/rtio/phy/sawg.py index fb520e968..b9abc64a5 100644 --- a/artiq/gateware/rtio/phy/sawg.py +++ b/artiq/gateware/rtio/phy/sawg.py @@ -3,20 +3,21 @@ from collections import namedtuple from migen import * from artiq.gateware.rtio import rtlink -from artiq.gateware.dsp.sawg import DDSFast +from artiq.gateware.dsp.sawg import Channel as _Channel _Phy = namedtuple("Phy", "rtlink probes overrides") -DDSFast_rtio = ClockDomainsRenamer("rio_phy")(DDSFast) +_ChannelPHY = ClockDomainsRenamer("rio_phy")(_Channel) -class Channel(DDSFast_rtio): +class Channel(_ChannelPHY): def __init__(self, *args, **kwargs): - DDSFast_rtio.__init__(self, *args, **kwargs) + _ChannelPHY.__init__(self, *args, **kwargs) self.phys = [] for i in self.i: - rl = rtlink.Interface(rtlink.OInterface(len(i.payload))) + rl = rtlink.Interface(rtlink.OInterface( + min(32, len(i.payload)))) # TODO: test/expand self.comb += [ i.stb.eq(rl.o.stb), rl.o.busy.eq(~i.ack), @@ -24,4 +25,5 @@ class Channel(DDSFast_rtio): ] # no probes, overrides self.phys.append(_Phy(rl, [], [])) - self.phys_names = dict(zip("afp", self.phys)) + self.phys_names = dict(zip("cfg f0 p0 a1 f1 p1 a2 f2 p2".split(), + self.phys)) From 65b2e4464ccbd769711861accedd0195fc80258c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 27 Oct 2016 14:14:56 +0200 Subject: [PATCH 079/157] phaser: sysref/sync diff term --- artiq/gateware/phaser.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/gateware/phaser.py b/artiq/gateware/phaser.py index d72e6c153..4673b7b90 100644 --- a/artiq/gateware/phaser.py +++ b/artiq/gateware/phaser.py @@ -25,16 +25,19 @@ fmc_adapter_io = [ Subsignal("p", Pins("HPC:LA00_CC_P")), Subsignal("n", Pins("HPC:LA00_CC_N")), IOStandard("LVDS_25"), + Misc("DIFF_TERM=TRUE"), ), ("ad9154_sync", 0, Subsignal("p", Pins("HPC:LA01_CC_P")), Subsignal("n", Pins("HPC:LA01_CC_N")), IOStandard("LVDS_25"), + Misc("DIFF_TERM=TRUE"), ), ("ad9154_sync", 1, Subsignal("p", Pins("HPC:LA02_P")), Subsignal("n", Pins("HPC:LA02_N")), IOStandard("LVDS_25"), + Misc("DIFF_TERM=TRUE"), ), ("ad9154_jesd", 0, # AD9154's SERIND7 Subsignal("txp", Pins("HPC:DP0_C2M_P")), From c428800caf52a77a22a9be0d967715cccb4e0b63 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 27 Oct 2016 15:39:39 +0200 Subject: [PATCH 080/157] phaser: spi, sma_gpio: 2.5 V --- artiq/gateware/phaser.py | 6 +++--- artiq/gateware/targets/kc705.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/phaser.py b/artiq/gateware/phaser.py index 4673b7b90..ca6185764 100644 --- a/artiq/gateware/phaser.py +++ b/artiq/gateware/phaser.py @@ -13,10 +13,10 @@ fmc_adapter_io = [ Subsignal("mosi", Pins("HPC:LA03_N")), Subsignal("miso", Pins("HPC:LA04_P")), Subsignal("en", Pins("HPC:LA05_N")), - IOStandard("LVTTL"), + IOStandard("LVCMOS25"), ), - ("ad9154_txen", 0, Pins("HPC:LA07_P"), IOStandard("LVTTL")), - ("ad9154_txen", 1, Pins("HPC:LA07_N"), IOStandard("LVTTL")), + ("ad9154_txen", 0, Pins("HPC:LA07_P"), IOStandard("LVCMOS25")), + ("ad9154_txen", 1, Pins("HPC:LA07_N"), IOStandard("LVCMOS25")), ("ad9154_refclk", 0, Subsignal("p", Pins("HPC:GBTCLK0_M2C_P")), Subsignal("n", Pins("HPC:GBTCLK0_M2C_N")), diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index f3abcd3ec..d6b1fede2 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -537,7 +537,7 @@ class Phaser(_NIST_Ions): rtio_channels = [] phy = ttl_serdes_7series.Inout_8X( - platform.request("user_sma_gpio_n_33")) + platform.request("user_sma_gpio_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=128)) From 8eff8586bb73c4af322693de3b5c544e5466e080 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 28 Oct 2016 01:57:55 +0200 Subject: [PATCH 081/157] moninj.rs: force u32 dds_ftws --- artiq/runtime.rs/src/moninj.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/runtime.rs/src/moninj.rs b/artiq/runtime.rs/src/moninj.rs index 13c8ef4cd..4db0aca0f 100644 --- a/artiq/runtime.rs/src/moninj.rs +++ b/artiq/runtime.rs/src/moninj.rs @@ -18,7 +18,7 @@ fn worker(socket: &mut UdpSocket) -> io::Result<()> { match request { Request::Monitor => { - let mut dds_ftws = [0; (csr::CONFIG_RTIO_DDS_COUNT as usize * + let mut dds_ftws = [0u32; (csr::CONFIG_RTIO_DDS_COUNT as usize * csr::CONFIG_DDS_CHANNELS_PER_BUS as usize)]; let mut reply = Reply::default(); @@ -54,7 +54,7 @@ fn worker(socket: &mut UdpSocket) -> io::Result<()> { csr::rtio_moninj::mon_probe_sel_write(i as u8); csr::rtio_moninj::mon_value_update_write(1); dds_ftws[(csr::CONFIG_DDS_CHANNELS_PER_BUS * j + i) as usize] = - csr::rtio_moninj::mon_value_read(); + csr::rtio_moninj::mon_value_read() as u32; } } } From 2a1e529dcf144f60e9277cbcb7be55153e347513 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 28 Oct 2016 01:58:08 +0200 Subject: [PATCH 082/157] phaser: DDS config dummies --- artiq/gateware/targets/kc705.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index d6b1fede2..57a31da9c 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -565,6 +565,15 @@ class Phaser(_NIST_Ions): self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) + + # FIXME: dummy + self.config["RTIO_FIRST_DDS_CHANNEL"] = 0 + self.config["RTIO_DDS_COUNT"] = 1 + self.config["DDS_CHANNELS_PER_BUS"] = 1 + self.config["DDS_AD9914"] = True + self.config["DDS_ONEHOT_SEL"] = True + self.config["DDS_RTIO_CLK_RATIO"] = 3 + self.add_rtio(rtio_channels, _PhaserCRG(platform, self.crg.cd_sys.clk)) self.comb += self.rtio_crg.refclk.eq(self.ad9154.jesd.cd_jesd.clk) From b14fcd41e4cfe388248958920e38e9291f0f3e18 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 28 Oct 2016 02:39:24 +0200 Subject: [PATCH 083/157] ksupport: add ad9154* --- artiq/runtime.rs/libksupport/api.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/artiq/runtime.rs/libksupport/api.rs b/artiq/runtime.rs/libksupport/api.rs index 46570feab..4670a20ea 100644 --- a/artiq/runtime.rs/libksupport/api.rs +++ b/artiq/runtime.rs/libksupport/api.rs @@ -117,4 +117,18 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(i2c_stop), api!(i2c_write), api!(i2c_read), + +// #if (defined CONFIG_AD9154_CS) + api!(ad9154_init), + api!(ad9154_write), + api!(ad9154_read), + + api!(ad9516_write), + api!(ad9516_read), + + api!(ad9154_jesd_enable), + api!(ad9154_jesd_ready), + api!(ad9154_jesd_prbs), + api!(ad9154_jesd_stpl), +// #endif ]; From d158c69be0ec23910d98ffc11a4065d3fca0634b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 5 Nov 2016 16:54:23 +0100 Subject: [PATCH 084/157] phaser: fix frequency comment --- artiq/gateware/targets/kc705.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 57a31da9c..0e1e33c16 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -415,7 +415,7 @@ class _PhaserCRG(Module, AutoCSR): # Warning: CLKINSEL=0 means CLKIN2 is selected i_CLKINSEL=~self._clock_sel.storage, - # VCO @ 1GHz when using 125MHz input + # VCO @ 1GHz when using 250MHz input p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=2, i_CLKFBIN=self.cd_rtio.clk, i_RST=self._pll_reset.storage, From 2e482505c67b3693ba16c8db4fc1d40a0269e337 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 13 Nov 2016 17:08:59 +0100 Subject: [PATCH 085/157] phaser: fix DDS dummy cfg --- artiq/gateware/targets/kc705.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index b8c73d825..b96450816 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -580,22 +580,25 @@ class Phaser(MiniSoC, AMPSoC): self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) - self.config["RTIO_FIRST_DDS_CHANNEL"] = 0 + 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_ONEHOT_SEL"] = 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.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.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) From 70a70320bd9b74a0766a40405ca909fbc3149971 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 13 Nov 2016 17:29:38 +0100 Subject: [PATCH 086/157] phaser: use misoc cordic --- artiq/gateware/dsp/cordic.py | 358 ----------------------------------- artiq/gateware/dsp/sawg.py | 2 +- 2 files changed, 1 insertion(+), 359 deletions(-) delete mode 100644 artiq/gateware/dsp/cordic.py diff --git a/artiq/gateware/dsp/cordic.py b/artiq/gateware/dsp/cordic.py deleted file mode 100644 index f09ca5031..000000000 --- a/artiq/gateware/dsp/cordic.py +++ /dev/null @@ -1,358 +0,0 @@ -# Copyright 2014-2015 Robert Jordens -# -# This file is part of redpid. -# -# redpid is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# redpid is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with redpid. If not, see . - -from math import atan, atanh, log, sqrt, pi - -from migen import * - - -class TwoQuadrantCordic(Module): - """Coordinate rotation digital computer - - Trigonometric, and arithmetic functions implemented using - additions/subtractions and shifts. - - http://eprints.soton.ac.uk/267873/1/tcas1_cordic_review.pdf - - http://www.andraka.com/files/crdcsrvy.pdf - - http://zatto.free.fr/manual/Volder_CORDIC.pdf - - The way the CORDIC is executed is controlled by `eval_mode`. - If `"iterative"` the stages are iteratively evaluated, one per clock - cycle. This mode uses the least amount of registers, but has the - lowest throughput and highest latency. If `"pipelined"` all stages - are executed in every clock cycle but separated by registers. This - mode has full throughput but uses many registers and has large - latency. If `"combinatorial"`, there are no registers, throughput is - maximal and latency is zero. `"pipelined"` and `"combinatorial"` use - the same number of shifters and adders. - - The type of trigonometric/arithmetic function is determined by - `cordic_mode` and `func_mode`. :math:`g` is the gain of the CORDIC. - - * rotate-circular: rotate the vector `(xi, yi)` by an angle `zi`. - Used to calculate trigonometric functions, `sin(), cos(), - tan() = sin()/cos()`, or to perform polar-to-cartesian coordinate - transformation: - - .. math:: - x_o = g \\cos(z_i) x_i - g \\sin(z_i) y_i - - y_o = g \\sin(z_i) x_i + g \\cos(z_i) y_i - - * vector-circular: determine length and angle of the vector - `(xi, yi)`. Used to calculate `arctan(), sqrt()` or - to perform cartesian-to-polar transformation: - - .. math:: - x_o = g\\sqrt{x_i^2 + y_i^2} - - z_o = z_i + \\tan^{-1}(y_i/x_i) - - * rotate-hyperbolic: hyperbolic functions of `zi`. Used to - calculate hyperbolic functions, `sinh, cosh, tanh = cosh/sinh, - exp = cosh + sinh`: - - .. math:: - x_o = g \\cosh(z_i) x_i + g \\sinh(z_i) y_i - - y_o = g \\sinh(z_i) x_i + g \\cosh(z_i) z_i - - * vector-hyperbolic: natural logarithm `ln(), arctanh()`, and - `sqrt()`. Use `x_i = a + b` and `y_i = a - b` to obtain `2* - sqrt(a*b)` and `ln(a/b)/2`: - - .. math:: - x_o = g\\sqrt{x_i^2 - y_i^2} - - z_o = z_i + \\tanh^{-1}(y_i/x_i) - - * rotate-linear: multiply and accumulate (not a very good - multiplier implementation): - - .. math:: - y_o = g(y_i + x_i z_i) - - * vector-linear: divide and accumulate: - - .. math:: - z_o = g(z_i + y_i/x_i) - - Parameters - ---------- - width : int - Bit width of the input and output signals. Defaults to 16. Input - and output signals are signed. - widthz : int - Bit with of `zi` and `zo`. Defaults to the `width`. - stages : int or None - Number of CORDIC incremental rotation stages. Defaults to - `width + min(1, guard)`. - guard : int or None - Add guard bits to the intermediate signals. If `None`, - defaults to `guard = log2(width)` which guarantees accuracy - to `width` bits. - eval_mode : str, {"iterative", "pipelined", "combinatorial"} - cordic_mode : str, {"rotate", "vector"} - func_mode : str, {"circular", "linear", "hyperbolic"} - Evaluation and arithmetic mode. See above. - - Attributes - ---------- - xi, yi, zi : Signal(width), in - Input values, signed. - xo, yo, zo : Signal(width), out - Output values, signed. - new_out : Signal(1), out - Asserted if output values are freshly updated in the current - cycle. - new_in : Signal(1), out - Asserted if new input values are being read in the next cycle. - zmax : float - `zi` and `zo` normalization factor. Floating point `zmax` - corresponds to `1<<(widthz - 1)`. `x` and `y` are scaled such - that floating point `1` corresponds to `1<<(width - 1)`. - gain : float - Cumulative, intrinsic gain and scaling factor. In circular mode - `sqrt(xi**2 + yi**2)` should be no larger than `2**(width - 1)/gain` - to prevent overflow. Additionally, in hyperbolic and linear mode, - the operation itself can cause overflow. - interval : int - Output interval in clock cycles. Inverse throughput. - latency : int - Input-to-output latency. The result corresponding to the inputs - appears at the outputs `latency` cycles later. - - Notes - ----- - - Each stage `i` in the CORDIC performs the following operation: - - .. math:: - x_{i+1} = x_i - m d_i y_i r^{-s_{m,i}}, - - y_{i+1} = y_i + d_i x_i r^{-s_{m,i}}, - - z_{i+1} = z_i - d_i a_{m,i}, - - where: - - * :math:`d_i`: clockwise or counterclockwise, determined by - `sign(z_i)` in rotate mode or `sign(-y_i)` in vector mode. - - * :math:`r`: radix of the number system (2) - - * :math:`m`: 1: circular, 0: linear, -1: hyperbolic - - * :math:`s_{m,i}`: non decreasing integer shift sequence - - * :math:`a_{m,i}`: elemetary rotation angle: :math:`a_{m,i} = - \\tan^{-1}(\\sqrt{m} s_{m,i})/\\sqrt{m}`. - """ - def __init__(self, width=16, widthz=None, stages=None, guard=0, - eval_mode="iterative", cordic_mode="rotate", - func_mode="circular"): - # validate parameters - assert eval_mode in ("combinatorial", "pipelined", "iterative") - assert cordic_mode in ("rotate", "vector") - assert func_mode in ("circular", "linear", "hyperbolic") - self.cordic_mode = cordic_mode - self.func_mode = func_mode - if guard is None: - # guard bits to guarantee "width" accuracy - guard = int(log(width)/log(2)) - if widthz is None: - widthz = width - if stages is None: - stages = width + min(1, guard) # cuts error below LSB - - # input output interface - self.xi = Signal((width, True)) - self.yi = Signal((width, True)) - self.zi = Signal((widthz, True)) - self.xo = Signal((width, True)) - self.yo = Signal((width, True)) - self.zo = Signal((widthz, True)) - self.new_in = Signal() - self.new_out = Signal() - - ### - - a, s, self.zmax, self.gain = self._constants(stages, widthz + guard) - stages = len(a) # may have increased due to repetitions - - if eval_mode == "iterative": - num_sig = 3 - self.interval = stages + 1 - self.latency = stages + 2 - else: - num_sig = stages + 1 - self.interval = 1 - if eval_mode == "pipelined": - self.latency = stages - else: # combinatorial - self.latency = 0 - - # inter-stage signals - x = [Signal((width + guard, True)) for i in range(num_sig)] - y = [Signal((width + guard, True)) for i in range(num_sig)] - z = [Signal((widthz + guard, True)) for i in range(num_sig)] - - # hook up inputs and outputs to the first and last inter-stage - # signals - self.comb += [ - x[0].eq(self.xi << guard), - y[0].eq(self.yi << guard), - z[0].eq(self.zi << guard), - self.xo.eq(x[-1] >> guard), - self.yo.eq(y[-1] >> guard), - self.zo.eq(z[-1] >> guard), - ] - - if eval_mode == "iterative": - # We afford one additional iteration for in/out. - i = Signal(max=stages + 1) - self.comb += [ - self.new_in.eq(i == stages), - self.new_out.eq(i == 1), - ] - ai = Signal((widthz + guard, True)) - self.sync += ai.eq(Array(a)[i]) - if range(stages) == s: - si = i - 1 # shortcut if no stage repetitions - else: - si = Signal(max=stages + 1) - self.sync += si.eq(Array(s)[i]) - xi, yi, zi = x[1], y[1], z[1] - self.sync += [ - self._stage(xi, yi, zi, xi, yi, zi, si, ai), - i.eq(i + 1), - If(i == stages, - i.eq(0), - ), - If(i == 0, - x[2].eq(xi), y[2].eq(yi), z[2].eq(zi), - xi.eq(x[0]), yi.eq(y[0]), zi.eq(z[0]), - ) - ] - else: - self.comb += [ - self.new_out.eq(1), - self.new_in.eq(1), - ] - for i, si in enumerate(s): - stmt = self._stage(x[i], y[i], z[i], - x[i + 1], y[i + 1], z[i + 1], - si, a[i]) - if eval_mode == "pipelined": - self.sync += stmt - else: # combinatorial - self.comb += stmt - - def _constants(self, stages, bits): - if self.func_mode == "circular": - s = range(stages) - a = [atan(2**-i) for i in s] - g = [sqrt(1 + 2**(-2*i)) for i in s] - #zmax = sum(a) - # use pi anyway as the input z can cause overflow - # and we need the range for quadrant mapping - zmax = pi - elif self.func_mode == "linear": - s = range(stages) - a = [2**-i for i in s] - g = [1 for i in s] - #zmax = sum(a) - # use 2 anyway as this simplifies a and scaling - zmax = 2. - else: # hyperbolic - s = [] - # need to repeat some stages: - j = 4 - for i in range(stages): - if i == j: - s.append(j) - j = 3*j + 1 - s.append(i + 1) - a = [atanh(2**-i) for i in s] - g = [sqrt(1 - 2**(-2*i)) for i in s] - zmax = sum(a)*2 - # round here helps the width=2**i - 1 case but hurts the - # important width=2**i case - cast = int - if log(bits)/log(2) % 1: - cast = round - a = [cast(ai*2**(bits - 1)/zmax) for ai in a] - gain = 1. - for gi in g: - gain *= gi - return a, s, zmax, gain - - def _stage(self, xi, yi, zi, xo, yo, zo, i, ai): - dir = Signal() - if self.cordic_mode == "rotate": - self.comb += dir.eq(zi < 0) - else: # vector - self.comb += dir.eq(yi >= 0) - dx = yi >> i - dy = xi >> i - dz = ai - if self.func_mode == "linear": - dx = 0 - elif self.func_mode == "hyperbolic": - dx = -dx - stmt = [ - xo.eq(xi + Mux(dir, dx, -dx)), - yo.eq(yi + Mux(dir, -dy, dy)), - zo.eq(zi + Mux(dir, dz, -dz)) - ] - return stmt - - -class Cordic(TwoQuadrantCordic): - """Four-quadrant CORDIC - - Same as :class:`TwoQuadrantCordic` but with support and convergence - for `abs(zi) > pi/2 in circular rotate mode or `xi < 0` in circular - vector mode. - """ - def __init__(self, **kwargs): - TwoQuadrantCordic.__init__(self, **kwargs) - if self.func_mode != "circular": - return # no need to remap quadrants - - cxi, cyi, czi = self.xi, self.yi, self.zi - self.xi = xi = Signal.like(cxi) - self.yi = yi = Signal.like(cyi) - self.zi = zi = Signal.like(czi) - - ### - - q = Signal() - if self.cordic_mode == "rotate": - self.comb += q.eq(zi[-2] ^ zi[-1]) - else: # vector - self.comb += q.eq(xi < 0) - self.comb += [ - If(q, - Cat(cxi, cyi, czi).eq( - Cat(-xi, -yi, zi + (1 << len(zi) - 1))) - ).Else( - Cat(cxi, cyi, czi).eq(Cat(xi, yi, zi)) - ) - ] diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 6d6fdb241..d23aa7865 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -1,7 +1,7 @@ from migen import * from misoc.interconnect.stream import Endpoint +from misoc.cores.cordic import Cordic -from .cordic import Cordic from .accu import PhasedAccu from .tools import eqh From 424a1f8f4e1af575fc171d55746d7a93e65b9a1e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 16 Nov 2016 13:39:19 +0100 Subject: [PATCH 087/157] dsp: move test tools --- artiq/gateware/dsp/tools.py | 45 ---------------------------- artiq/test/gateware/test_accu.py | 2 +- artiq/test/gateware/test_sawg.py | 2 +- artiq/test/gateware/test_sawg_phy.py | 2 +- artiq/test/gateware/test_spline.py | 2 +- artiq/test/gateware/tools.py | 43 ++++++++++++++++++++++++++ 6 files changed, 47 insertions(+), 49 deletions(-) create mode 100644 artiq/test/gateware/tools.py diff --git a/artiq/gateware/dsp/tools.py b/artiq/gateware/dsp/tools.py index 1e220ecce..5ae78bd8c 100644 --- a/artiq/gateware/dsp/tools.py +++ b/artiq/gateware/dsp/tools.py @@ -4,32 +4,6 @@ from functools import reduce from migen import * -def set_dict(e, **k): - for k, v in k.items(): - if isinstance(v, dict): - yield from set_dict(getattr(e, k), **v) - else: - yield getattr(e, k).eq(v) - - -def xfer(dut, **kw): - ep = [] - for e, v in kw.items(): - e = getattr(dut, e) - yield from set_dict(e, **v) - ep.append(e) - for e in ep: - yield e.stb.eq(1) - while ep: - yield - for e in ep[:]: - if hasattr(e, "busy") and (yield e.busy): - raise ValueError(e, "busy") - if not hasattr(e, "ack") or (yield e.ack): - yield e.stb.eq(0) - ep.remove(e) - - class Delay(Module): def __init__(self, i, delay, o=None): if isinstance(i, (int, tuple)): @@ -73,22 +47,3 @@ class SatAddMixin: ) ] return s0 - - -def szip(*iters): - active = {it: None for it in iters} - while active: - for it in list(active): - while True: - try: - val = it.send(active[it]) - except StopIteration: - del active[it] - break - if val is None: - break - else: - active[it] = (yield val) - val = (yield None) - for it in active: - active[it] = val diff --git a/artiq/test/gateware/test_accu.py b/artiq/test/gateware/test_accu.py index 4bc7066fb..384fba9cc 100644 --- a/artiq/test/gateware/test_accu.py +++ b/artiq/test/gateware/test_accu.py @@ -4,7 +4,7 @@ from migen import * from migen.fhdl.verilog import convert from artiq.gateware.dsp.accu import Accu, PhasedAccu -from artiq.gateware.dsp.tools import xfer +from .tools import xfer def read(o, n): diff --git a/artiq/test/gateware/test_sawg.py b/artiq/test/gateware/test_sawg.py index 4ffd4ba78..00e5f8c3f 100644 --- a/artiq/test/gateware/test_sawg.py +++ b/artiq/test/gateware/test_sawg.py @@ -4,7 +4,7 @@ from migen import * from migen.fhdl.verilog import convert from artiq.gateware.dsp.sawg import DDSFast -from artiq.gateware.dsp.tools import xfer +from .tools import xfer def _test_gen_dds(dut, o): diff --git a/artiq/test/gateware/test_sawg_phy.py b/artiq/test/gateware/test_sawg_phy.py index 5b922968f..4f2617c7a 100644 --- a/artiq/test/gateware/test_sawg_phy.py +++ b/artiq/test/gateware/test_sawg_phy.py @@ -4,7 +4,7 @@ from migen import * from migen.fhdl.verilog import convert from artiq.gateware.rtio.phy.sawg import Channel -from artiq.gateware.dsp.tools import xfer, szip +from .tools import xfer, szip def rtio_xfer(dut, **kwargs): diff --git a/artiq/test/gateware/test_spline.py b/artiq/test/gateware/test_spline.py index 6fca4f555..fe2d82c28 100644 --- a/artiq/test/gateware/test_spline.py +++ b/artiq/test/gateware/test_spline.py @@ -4,7 +4,7 @@ from migen import * from migen.fhdl.verilog import convert from artiq.gateware.dsp.spline import Spline -from artiq.gateware.dsp.tools import xfer +from .tools import xfer def _test_gen_spline(dut, o): diff --git a/artiq/test/gateware/tools.py b/artiq/test/gateware/tools.py new file mode 100644 index 000000000..ca9451e78 --- /dev/null +++ b/artiq/test/gateware/tools.py @@ -0,0 +1,43 @@ +def set_dict(e, **k): + for k, v in k.items(): + if isinstance(v, dict): + yield from set_dict(getattr(e, k), **v) + else: + yield getattr(e, k).eq(v) + + +def xfer(dut, **kw): + ep = [] + for e, v in kw.items(): + e = getattr(dut, e) + yield from set_dict(e, **v) + ep.append(e) + for e in ep: + yield e.stb.eq(1) + while ep: + yield + for e in ep[:]: + if hasattr(e, "busy") and (yield e.busy): + raise ValueError(e, "busy") + if not hasattr(e, "ack") or (yield e.ack): + yield e.stb.eq(0) + ep.remove(e) + + +def szip(*iters): + active = {it: None for it in iters} + while active: + for it in list(active): + while True: + try: + val = it.send(active[it]) + except StopIteration: + del active[it] + break + if val is None: + break + else: + active[it] = (yield val) + val = (yield None) + for it in active: + active[it] = val From 98193d6fa13b39088317a4dead65d0c336462b9e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 17 Nov 2016 02:36:29 +0100 Subject: [PATCH 088/157] dsp/Delay: reset_less --- artiq/gateware/dsp/tools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/dsp/tools.py b/artiq/gateware/dsp/tools.py index 5ae78bd8c..b7f2ff2af 100644 --- a/artiq/gateware/dsp/tools.py +++ b/artiq/gateware/dsp/tools.py @@ -7,13 +7,13 @@ from migen import * class Delay(Module): def __init__(self, i, delay, o=None): if isinstance(i, (int, tuple)): - z = [Signal(i) for j in range(delay + 1)] + z = [Signal(i, reset_less=True) for j in range(delay + 1)] elif isinstance(i, list): z = [Record(i) for j in range(delay + 1)] elif isinstance(i, Record): z = [Record(i.layout) for j in range(delay + 1)] else: - z = [Signal.like(i) for j in range(delay + 1)] + z = [Signal.like(i, reset_less=True) for j in range(delay + 1)] self.i = z[0] self.o = z[-1] if not isinstance(i, (int, list, tuple)): From 51f23feeacc25586616f277967b5935ddb2ea40e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 17 Nov 2016 02:36:49 +0100 Subject: [PATCH 089/157] dsp: implement sawg features --- artiq/gateware/dsp/sawg.py | 420 +++++++++++-------------------------- 1 file changed, 121 insertions(+), 299 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 75ac80b39..14c16d41f 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -1,354 +1,176 @@ +from collections import namedtuple + from migen import * from misoc.interconnect.stream import Endpoint from misoc.cores.cordic import Cordic from .accu import PhasedAccu, Accu -from .tools import eqh, Delay +from .tools import eqh, Delay, SatAddMixin from .spline import Spline -class DDSFast(Module): - def __init__(self, width, parallelism=4): - a_width = width - p_width = width - f_width = 2*width +_Widths = namedtuple("_Widths", "t a p f") +_Orders = namedtuple("_Orders", "a p f") - self.o = [Signal((width, True)) for i in range(parallelism)] - self.width = width +class ParallelDDS(Module): + def __init__(self, widths, parallelism=1, a_delay=0): + self.i = Endpoint([("x", widths.a), ("y", widths.a), + ("f", widths.f), ("p", widths.f), ("clr", 1)]) self.parallelism = parallelism - self.latency = 1 # will be accumulated - - q = PhasedAccu(f_width, parallelism) - self.submodules += q - self.latency += q.latency - - self.a = Endpoint([("a", a_width)]) - self.f = Endpoint([("f", f_width)]) - self.p = Endpoint([("p", p_width)]) - self.i = [self.a, self.f, self.p] + self.widths = widths ### - a = Signal.like(self.a.a) - self.sync += [ - If(self.a.stb, - a.eq(self.a.a) - ), - If(self.f.stb, - eqh(q.i.f, self.f.f) - ), - q.i.clr.eq(0), - If(self.p.stb, - eqh(q.i.p, self.p.p), - q.i.clr.eq(1) - ), - q.i.stb.eq(self.f.stb | self.p.stb), - ] + accu = PhasedAccu(widths.f, parallelism) + cordic = [Cordic(width=widths.a, widthz=widths.p, guard=None, + eval_mode="pipelined") for i in range(parallelism)] + self.xo = [c.xo for c in cordic] + self.yo = [c.yo for c in cordic] + a_delay += accu.latency + xy_delay = Delay(2*widths.a, max(0, a_delay)) + z_delay = Delay(parallelism*widths.p, max(0, -a_delay)) + self.submodules += accu, xy_delay, z_delay, cordic + self.latency = max(0, a_delay) + cordic[0].latency + self.gain = cordic[0].gain + self.comb += [ - self.a.ack.eq(1), - self.f.ack.eq(1), - self.p.ack.eq(1), - q.o.ack.eq(1), + xy_delay.i.eq(Cat(self.i.x, self.i.y)), + z_delay.i.eq(Cat([zi[-widths.p:] + for zi in accu.o.payload.flatten()])), + eqh(accu.i.p, self.i.p), + accu.i.f.eq(self.i.f), + accu.i.clr.eq(self.i.clr), + accu.i.stb.eq(self.i.stb), + self.i.ack.eq(accu.i.ack), + accu.o.ack.eq(1), + [Cat(c.xi, c.yi).eq(xy_delay.o) for c in cordic], + Cat([c.zi for c in cordic]).eq(z_delay.o), ] - c = [] - for i in range(parallelism): - ci = Cordic(width=width, widthz=p_width, - guard=None, eval_mode="pipelined") - self.submodules += ci - c.append(ci) - qoi = getattr(q.o, "z{}".format(i)) - self.comb += [ - eqh(ci.xi, a), - ci.yi.eq(0), - eqh(ci.zi, qoi), - eqh(self.o[i], ci.xo), - ] - self.latency += c[0].latency - self.gain = c[0].gain - -class DDSFast(Module): - def __init__(self, width, t_width=None, - a_width=None, p_width=None, f_width=None, - a_order=4, p_order=1, f_order=2, parallelism=8): - if t_width is None: - t_width = width - if a_width is None: - a_width = width + (a_order - 1)*t_width - if p_width is None: - p_width = width + (p_order - 1)*t_width - if f_width is None: - f_width = width + (f_order + 1)*t_width - a = Spline(order=a_order, width=a_width) - p = Spline(order=p_order, width=p_width) - f = Spline(order=f_order, width=f_width) - self.submodules += a, p, f - - self.a = a.tri(t_width) - self.f = f.tri(t_width) - self.p = p.tri(t_width) - self.i = [self.a, self.f, self.p] - self.o = [[Signal((width, True)) for i in range(2)] - for i in range(parallelism)] - self.parallelism = parallelism - self.latency = 0 # will be accumulated +class SplineParallelDUC(ParallelDDS): + def __init__(self, widths, orders, **kwargs): + p = Spline(order=orders.p, width=widths.p) + f = Spline(order=orders.f, width=widths.f) + self.f = f.tri(widths.t) + self.p = p.tri(widths.t) + self.submodules += p, f + self.ce = Signal(reset=1) + self.clr = Signal() + super().__init__(widths._replace(p=len(self.f.a0), f=len(self.f.a0)), + **kwargs) + self.latency += f.latency ### - self.latency += p.latency - q = PhasedAccu(f_width, parallelism) - self.submodules += q - self.latency += q.latency - da = [Signal((width, True)) for i in range(q.latency)] + assert p.latency == f.latency - self.sync += [ - If(q.i.stb & q.i.ack, - eqh(da[0], a.o.a0), - [da[i + 1].eq(da[i]) for i in range(len(da) - 1)], - ), - If(p.o.stb & p.o.ack, - q.i.clr.eq(0), - ), - If(p.i.stb & p.i.ack, - q.i.clr.eq(self.clr), - ), + self.comb += [ + p.o.ack.eq(self.ce), + f.o.ack.eq(self.ce), + eqh(self.i.f, f.o.a0), + eqh(self.i.p, p.o.a0), + self.i.clr.eq(self.clr), + self.i.stb.eq(p.o.stb & f.o.stb), ] + + +class SplineParallelDDS(SplineParallelDUC): + def __init__(self, widths, orders, **kwargs): + a = Spline(order=orders.a, width=widths.a) + self.a = a.tri(widths.t) + self.submodules += a + super().__init__(widths._replace(a=len(self.a.a0)), + orders, **kwargs) + + ### + self.comb += [ a.o.ack.eq(self.ce), - p.o.ack.eq(self.ce), - f.o.ack.eq(self.ce), - q.i.stb.eq(self.ce), - eqh(q.i.p, p.o.a0), - q.i.f.eq(f.o.a0), - q.o.ack.eq(1), + eqh(self.i.x, a.o.a0), + self.i.y.eq(0), ] - c = [] - for i in range(parallelism): - ci = Cordic(width=width, widthz=p_width, - guard=None, eval_mode="pipelined") - self.submodules += ci - c.append(ci) - qoi = getattr(q.o, "z{}".format(i)) - self.comb += [ - ci.xi.eq(da[-1]), - ci.yi.eq(0), - eqh(ci.zi, qoi), - eqh(self.o[i][0], ci.xo), - eqh(self.o[i][1], ci.yo), - ] - self.latency += c[0].latency - self.gain = c[0].gain - - -class DDSSlow(Module): - def __init__(self, width, t_width, a_width, p_width, f_width, - a_order=4, p_order=1, f_order=2): - a = Spline(order=a_order, width=a_width) - p = Spline(order=p_order, width=p_width) - f = Spline(order=f_order, width=f_width) - self.submodules += a, p, f - - self.a = a.tri(t_width) - self.f = f.tri(t_width) - self.p = p.tri(t_width) - self.i = [self.a, self.f, self.p] - self.i_names = "a f p".split() - self.o = [Signal((width, True)) for i in range(2)] - self.ce = Signal() - self.clr = Signal() - self.latency = 0 # will be accumulated - - ### - - self.latency += p.latency - q = Accu(f_width) - self.latency += q.latency - da = CEInserter()(Delay)(width, q.latency) - c = Cordic(width=width, widthz=p_width, - guard=None, eval_mode="pipelined") - self.latency += c.latency - self.gain = c.gain - self.submodules += q, da, c - - self.sync += [ - If(p.o.stb & p.o.ack, - q.i.clr.eq(0), - ), - If(p.i.stb & p.i.ack, - q.i.clr.eq(self.clr), - ), - ] - self.comb += [ - da.ce.eq(q.i.stb & q.i.ack), - a.o.ack.eq(self.ce), - p.o.ack.eq(self.ce), - f.o.ack.eq(self.ce), - q.i.stb.eq(self.ce), - eqh(da.i, a.o.a0), - eqh(q.i.p, p.o.a0), - q.i.f.eq(f.o.a0), - q.o.ack.eq(1), - c.xi.eq(da.o), - c.yi.eq(0), - eqh(c.zi, q.o.z), - eqh(self.o[0], c.xo), - eqh(self.o[1], c.yo), - ] - - -class DDS(Module): - def __init__(self, width, t_width=None, - a_width=None, p_width=None, f_width=None, - a_order=4, p_order=1, f_order=2, parallelism=8): - if t_width is None: - t_width = width - if a_width is None: - a_width = width + (a_order - 1)*t_width - if p_width is None: - p_width = width + (p_order - 1)*t_width - if f_width is None: - f_width = width + (f_order + 1)*t_width - self.b = [DDSSlow(width, t_width, a_width, p_width, f_width, a_order, - p_order, f_order) for i in range(2)] - p = Spline(order=1, width=p_width) - f = Spline(order=1, width=f_width) - self.submodules += self.b, p, f - - self.f0 = f.tri(t_width) - self.p0 = p.tri(t_width) - self.i = [self.f0, self.p0] - self.i_names = "f0 p0".split() - for i, bi in enumerate(self.b): - self.i += bi.i - for ii in bi.i_names: - self.i_names.append("{}{}".format(ii, i + 1)) - for j in "afp": - setattr(self, "{}{}".format(j, i + 1), getattr(bi, j)) - self.o = [[Signal((width, True)) for i in range(2)] - for i in range(parallelism)] - self.ce = Signal() - self.clr = Signal() - self.parallelism = parallelism - self.latency = 0 # will be accumulated - - ### - - self.latency += self.b[0].latency # TODO: f0/p0, q.latency delta - q = PhasedAccu(f_width, parallelism) - self.submodules += q - - self.sync += [ - If(p.o.stb & p.o.ack, - q.i.clr.eq(0), - ), - If(p.i.stb & p.i.ack, - q.i.clr.eq(self.clr), - ), - ] - self.comb += [ - [bi.ce.eq(self.ce) for bi in self.b], - [bi.clr.eq(self.clr) for bi in self.b], - p.o.ack.eq(self.ce), - f.o.ack.eq(self.ce), - q.i.stb.eq(self.ce), - eqh(q.i.p, p.o.a0), - eqh(q.i.f, f.o.a0), - q.o.ack.eq(1), - ] - x = self.sat_add(bi.o[0] for bi in self.b) - y = self.sat_add(bi.o[1] for bi in self.b) - - c = [] - for i in range(parallelism): - ci = Cordic(width=width, widthz=p_width, - guard=None, eval_mode="pipelined") - self.submodules += ci - c.append(ci) - qoi = getattr(q.o, "z{}".format(i)) - self.comb += [ - ci.xi.eq(x), - ci.yi.eq(y), - eqh(ci.zi, qoi), - eqh(self.o[i][0], ci.xo), - eqh(self.o[i][1], ci.yo), - ] - self.latency += c[0].latency - self.gain = self.b[0].gain * c[0].gain - class Config(Module): def __init__(self): - self.cfg = Record([("tap", 5), ("clr", 1), ("iq", 2)]) - self.i = Endpoint(self.cfg.layout) + self.clr = Signal(4) + self.iq_en = Signal(2) + limit = [Signal((16, True)) for i in range(2*2)] + self.limit = [limit[i:i + 2] for i in range(0, len(limit), 2)] + self.i = Endpoint([("addr", bits_for(len(limit) + 2)), ("data", 16)]) self.ce = Signal() ### - n = Signal(1 << len(self.i.tap)) - tap = Signal.like(self.i.tap) - clk = Signal() - clk0 = Signal() + div = Signal(16) + n = Signal.like(div) + + reg = Array([Cat(self.clr, self.iq_en), Cat(div, n)] + self.limit) self.comb += [ self.i.ack.eq(1), - clk.eq(Array(n)[tap]), + self.ce.eq(n == 0), ] self.sync += [ - clk0.eq(clk), - self.ce.eq(0), - If(clk0 ^ clk, - self.ce.eq(1), + n.eq(n - 1), + If(self.ce, + n.eq(div), ), - n.eq(n + 1), If(self.i.stb, - n.eq(0), - self.cfg.eq(self.i.payload), + reg[self.i.addr].eq(self.i.data), ), ] -class Channel(Module): - def __init__(self, width=16, t_width=None, u_order=4, **kwargs): - if t_width is None: - t_width = width - du = Spline(width=width + (u_order - 1)*t_width, order=u_order) - da = DDS(width, t_width, **kwargs) +class Channel(Module, SatAddMixin): + def __init__(self, width=16, parallelism=4, widths=None, orders=None): + if orders is None: + orders = _Orders(a=4, f=2, p=1) + if widths is None: + widths = _Widths(t=width, a=orders.a*width, p=orders.p*width, + f=3*width + (orders.f - 1)*width) + cfg = Config() - self.submodules += du, da, cfg - self.i = [cfg.i, du.tri(t_width)] + da.i - self.i_names = "cfg u".split() + da.i_names - self.q_i = [Signal((width, True)) for i in range(da.parallelism)] - self.q_o = [ai[1] for ai in da.o] - self.o = [Signal((width, True)) for i in range(da.parallelism)] - self.width = width - self.parallelism = da.parallelism - self.latency = da.latency + 1 - self.cordic_gain = da.gain + a1 = SplineParallelDDS(widths, orders) + a2 = SplineParallelDDS(widths, orders) + b = SplineParallelDUC(widths, orders, parallelism=parallelism, + a_delay=-a1.latency) + u = Spline(width=widths.a, order=orders.a) + du = Delay(widths.a, a1.latency + b.latency - u.latency) + self.submodules += cfg, a1, a2, b, u, du + self.cfg = cfg.i + self.u = u.tri(widths.t) + self.i = [self.cfg, self.u, a1.a, a1.f, a1.p, a2.a, a2.f, a2.p, b.f, b.p] + self.y_in = [Signal((width, True)) for i in range(b.parallelism)] + self.y_out = b.yo + self.o = [Signal((width, True)) for i in range(b.parallelism)] + self.widths = widths + self.orders = orders + self.parallelism = parallelism + self.latency = a1.latency + b.latency + 1 + self.cordic_gain = a1.gain*b.gain ### - # delay du to match da - ddu = Delay((width, True), da.latency - du.latency) - self.submodules += ddu self.comb += [ - ddu.i.eq(du.o.a0[-width:]), - da.clr.eq(cfg.cfg.clr), - da.ce.eq(cfg.ce), - du.o.ack.eq(cfg.ce), + a1.ce.eq(cfg.ce), + a2.ce.eq(cfg.ce), + b.ce.eq(cfg.ce), + u.o.ack.eq(cfg.ce), + Cat(a1.clr, a2.clr, b.clr).eq(cfg.clr), + b.i.x.eq(self.sat_add([a1.xo[0], a2.xo[0]])), + b.i.y.eq(self.sat_add([a1.yo[0], a2.yo[0]])), + eqh(du.i, u.o.a0), ] # wire up outputs and q_{i,o} exchange - for oi, ai, qi in zip(self.o, da.o, self.q_i): + for o, x, y in zip(self.o, b.xo, self.y_in): self.sync += [ - oi.eq(self.sat_add([ - ddu.o + - # du.o.a0[-width:], - Mux(cfg.cfg.iq[0], ai[0], 0), - Mux(cfg.cfg.iq[1], qi, 0)])), + o.eq(self.sat_add([du.o, + Mux(cfg.iq_en[0], x, 0), + Mux(cfg.iq_en[1], y, 0)])), ] - def connect_q(self, buddy): - for i, qi in enumerate(self.q_i): - self.comb += qi.eq(buddy.q_o[i]) + def connect_q_from(self, buddy): + self.comb += Cat(self.y_in).eq(Cat(buddy.y_out)) From d678bb3fb6e10bcac4dd5b6a609ef6400d6ccf41 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 18 Nov 2016 15:23:56 +0100 Subject: [PATCH 090/157] phaser: update sawg tests --- artiq/gateware/dsp/sawg.py | 68 ++++++++++++++++------------ artiq/gateware/rtio/phy/sawg.py | 10 ++-- artiq/test/gateware/test_sawg.py | 14 +++--- artiq/test/gateware/test_sawg_phy.py | 31 ++++++++----- artiq/test/gateware/tools.py | 6 +++ 5 files changed, 78 insertions(+), 51 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 14c16d41f..2615d2018 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -36,8 +36,8 @@ class ParallelDDS(Module): self.comb += [ xy_delay.i.eq(Cat(self.i.x, self.i.y)), - z_delay.i.eq(Cat([zi[-widths.p:] - for zi in accu.o.payload.flatten()])), + z_delay.i.eq(Cat(zi[-widths.p:] + for zi in accu.o.payload.flatten())), eqh(accu.i.p, self.i.p), accu.i.f.eq(self.i.f), accu.i.clr.eq(self.i.clr), @@ -45,7 +45,7 @@ class ParallelDDS(Module): self.i.ack.eq(accu.i.ack), accu.o.ack.eq(1), [Cat(c.xi, c.yi).eq(xy_delay.o) for c in cordic], - Cat([c.zi for c in cordic]).eq(z_delay.o), + Cat(c.zi for c in cordic).eq(z_delay.o), ] @@ -71,8 +71,15 @@ class SplineParallelDUC(ParallelDDS): f.o.ack.eq(self.ce), eqh(self.i.f, f.o.a0), eqh(self.i.p, p.o.a0), - self.i.clr.eq(self.clr), - self.i.stb.eq(p.o.stb & f.o.stb), + self.i.stb.eq(p.o.stb | f.o.stb), + ] + + assert p.latency == 1 + self.sync += [ + self.i.clr.eq(0), + If(p.i.stb, + self.i.clr.eq(self.clr), + ), ] @@ -94,20 +101,24 @@ class SplineParallelDDS(SplineParallelDUC): class Config(Module): - def __init__(self): - self.clr = Signal(4) - self.iq_en = Signal(2) - limit = [Signal((16, True)) for i in range(2*2)] - self.limit = [limit[i:i + 2] for i in range(0, len(limit), 2)] - self.i = Endpoint([("addr", bits_for(len(limit) + 2)), ("data", 16)]) + def __init__(self, width): + self.clr = Signal(4, reset=0b1111) + self.iq_en = Signal(2, reset=0b01) + self.limit = [[Signal((width, True), reset=-(1 << width - 1)), + Signal((width, True), reset=(1 << width - 1) - 1)] + for i in range(2)] + self.i = Endpoint([("addr", bits_for(4 + 2*len(self.limit))), + ("data", 16)]) self.ce = Signal() ### - div = Signal(16) + div = Signal(16, reset=0) n = Signal.like(div) + pad = Signal() - reg = Array([Cat(self.clr, self.iq_en), Cat(div, n)] + self.limit) + reg = Array([Cat(div, n), self.clr, self.iq_en, pad] + + sum(self.limit, [])) self.comb += [ self.i.ack.eq(1), @@ -130,22 +141,22 @@ class Channel(Module, SatAddMixin): orders = _Orders(a=4, f=2, p=1) if widths is None: widths = _Widths(t=width, a=orders.a*width, p=orders.p*width, - f=3*width + (orders.f - 1)*width) + f=(orders.f + 2)*width) - cfg = Config() - a1 = SplineParallelDDS(widths, orders) - a2 = SplineParallelDDS(widths, orders) - b = SplineParallelDUC(widths, orders, parallelism=parallelism, - a_delay=-a1.latency) + self.submodules.a1 = a1 = SplineParallelDDS(widths, orders) + self.submodules.a2 = a2 = SplineParallelDDS(widths, orders) + self.submodules.b = b = SplineParallelDUC( + widths, orders, parallelism=parallelism, a_delay=-a1.latency) + cfg = Config(widths.a) u = Spline(width=widths.a, order=orders.a) du = Delay(widths.a, a1.latency + b.latency - u.latency) - self.submodules += cfg, a1, a2, b, u, du - self.cfg = cfg.i + self.submodules += cfg, u, du self.u = u.tri(widths.t) - self.i = [self.cfg, self.u, a1.a, a1.f, a1.p, a2.a, a2.f, a2.p, b.f, b.p] - self.y_in = [Signal((width, True)) for i in range(b.parallelism)] - self.y_out = b.yo - self.o = [Signal((width, True)) for i in range(b.parallelism)] + self.i = [cfg.i, self.u, a1.a, a1.f, a1.p, a2.a, a2.f, a2.p, b.f, b.p] + self.i_names = "cfg u a1 f1 p1 a2 f2 p2 f0 p0".split() + self.i_named = dict(zip(self.i_names, self.i)) + self.y_in = [Signal((width, True)) for i in range(parallelism)] + self.o = [Signal((width, True)) for i in range(parallelism)] self.widths = widths self.orders = orders self.parallelism = parallelism @@ -167,10 +178,11 @@ class Channel(Module, SatAddMixin): # wire up outputs and q_{i,o} exchange for o, x, y in zip(self.o, b.xo, self.y_in): self.sync += [ - o.eq(self.sat_add([du.o, + o.eq(self.sat_add([ + du.o, Mux(cfg.iq_en[0], x, 0), Mux(cfg.iq_en[1], y, 0)])), ] - def connect_q_from(self, buddy): - self.comb += Cat(self.y_in).eq(Cat(buddy.y_out)) + def connect_y(self, buddy): + self.comb += Cat(buddy.y_in).eq(Cat(self.b.yo)) diff --git a/artiq/gateware/rtio/phy/sawg.py b/artiq/gateware/rtio/phy/sawg.py index b9abc64a5..84094f5a2 100644 --- a/artiq/gateware/rtio/phy/sawg.py +++ b/artiq/gateware/rtio/phy/sawg.py @@ -16,14 +16,12 @@ class Channel(_ChannelPHY): _ChannelPHY.__init__(self, *args, **kwargs) self.phys = [] for i in self.i: - rl = rtlink.Interface(rtlink.OInterface( - min(32, len(i.payload)))) # TODO: test/expand + rl = rtlink.Interface(rtlink.OInterface(len(i.payload))) self.comb += [ i.stb.eq(rl.o.stb), rl.o.busy.eq(~i.ack), - Cat(i.payload.flatten()).eq(rl.o.data), + i.payload.raw_bits().eq(rl.o.data), ] - # no probes, overrides + # TODO probes, overrides self.phys.append(_Phy(rl, [], [])) - self.phys_names = dict(zip("cfg f0 p0 a1 f1 p1 a2 f2 p2".split(), - self.phys)) + self.phys_named = dict(zip(self.i_names, self.phys)) diff --git a/artiq/test/gateware/test_sawg.py b/artiq/test/gateware/test_sawg.py index 00e5f8c3f..a5eea31bd 100644 --- a/artiq/test/gateware/test_sawg.py +++ b/artiq/test/gateware/test_sawg.py @@ -3,23 +3,25 @@ import numpy as np from migen import * from migen.fhdl.verilog import convert -from artiq.gateware.dsp.sawg import DDSFast +from artiq.gateware.dsp import sawg from .tools import xfer def _test_gen_dds(dut, o): yield from xfer(dut, - a=dict(a=10), - p=dict(p=0), - f=dict(f=1 << 8), + a=dict(a0=10), + p=dict(a0=0), + f=dict(a0=1), ) for i in range(256//dut.parallelism): yield - o.append((yield from [(yield _) for _ in dut.o])) + o.append((yield from [(yield _) for _ in dut.xo])) def _test_channel(): - dut = DDSFast(width=8, parallelism=2) + widths = sawg._Widths(t=8, a=4*8, p=8, f=16) + orders = sawg._Orders(a=4, p=1, f=2) + dut = sawg.SplineParallelDDS(widths, orders, parallelism=2) if False: print(convert(dut)) diff --git a/artiq/test/gateware/test_sawg_phy.py b/artiq/test/gateware/test_sawg_phy.py index 4f2617c7a..35666a5f6 100644 --- a/artiq/test/gateware/test_sawg_phy.py +++ b/artiq/test/gateware/test_sawg_phy.py @@ -1,25 +1,32 @@ import numpy as np +from operator import or_ from migen import * from migen.fhdl.verilog import convert from artiq.gateware.rtio.phy.sawg import Channel -from .tools import xfer, szip +from .tools import rtio_xfer -def rtio_xfer(dut, **kwargs): - yield from szip(*( - xfer(dut.phys_names[k].rtlink, o={"data": v}) - for k, v in kwargs.items())) +def pack_tri(port, *v): + r = 0 + w = 0 + for vi, p in zip(v, port.payload.flatten()): + w += len(p) + r |= int(vi*(1 << w)) + return r def gen_rtio(dut): - width = dut.width yield yield from rtio_xfer( - dut, a=int(.1 * (1 << width)), - f=int(.01234567 * (1 << 2*width)), - p=0) + dut, + a1=pack_tri(dut.a1.a, .1), + f0=pack_tri(dut.b.f, .01234567), + f1=pack_tri(dut.a1.f, .01234567), + a2=pack_tri(dut.a1.a, .05), + f2=pack_tri(dut.a1.f, .00534567), + ) def gen_log(dut, o, n): @@ -28,10 +35,12 @@ def gen_log(dut, o, n): for i in range(n): yield o.append((yield from [(yield _) for _ in dut.o])) + #o.append([(yield dut.a1.xo[0])]) def _test_channel(): width = 16 + dut = ClockDomainsRenamer({"rio_phy": "sys"})( Channel(width=width, parallelism=4) ) @@ -43,8 +52,8 @@ def _test_channel(): o = [] run_simulation( dut, - [gen_rtio(dut), gen_log(dut, o, 256 * 2)], - ) # vcd_name="dds.vcd") + [gen_rtio(dut), gen_log(dut, o, 128)], + vcd_name="dds.vcd") o = np.array(o)/(1 << (width - 1)) o = o.ravel() np.savez_compressed("dds.npz", o=o) diff --git a/artiq/test/gateware/tools.py b/artiq/test/gateware/tools.py index ca9451e78..8d22ad475 100644 --- a/artiq/test/gateware/tools.py +++ b/artiq/test/gateware/tools.py @@ -41,3 +41,9 @@ def szip(*iters): val = (yield None) for it in active: active[it] = val + + +def rtio_xfer(dut, **kwargs): + yield from szip(*( + xfer(dut.phys_named[k].rtlink, o={"data": v}) + for k, v in kwargs.items())) From 14ddcd2e30bfed631cafd400de278fea739159d8 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 18 Nov 2016 15:25:42 +0100 Subject: [PATCH 091/157] Revert "dsp/Delay: reset_less" for now This reverts commit 98193d6fa13b39088317a4dead65d0c336462b9e. --- artiq/gateware/dsp/tools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/dsp/tools.py b/artiq/gateware/dsp/tools.py index b7f2ff2af..5ae78bd8c 100644 --- a/artiq/gateware/dsp/tools.py +++ b/artiq/gateware/dsp/tools.py @@ -7,13 +7,13 @@ from migen import * class Delay(Module): def __init__(self, i, delay, o=None): if isinstance(i, (int, tuple)): - z = [Signal(i, reset_less=True) for j in range(delay + 1)] + z = [Signal(i) for j in range(delay + 1)] elif isinstance(i, list): z = [Record(i) for j in range(delay + 1)] elif isinstance(i, Record): z = [Record(i.layout) for j in range(delay + 1)] else: - z = [Signal.like(i, reset_less=True) for j in range(delay + 1)] + z = [Signal.like(i) for j in range(delay + 1)] self.i = z[0] self.o = z[-1] if not isinstance(i, (int, list, tuple)): From 7664b226f2d6cee9c47866bdc0d0d991372c61a1 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 18 Nov 2016 15:34:03 +0100 Subject: [PATCH 092/157] phaser/conda: bump jesd204b --- conda/artiq-kc705-phaser/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-kc705-phaser/meta.yaml b/conda/artiq-kc705-phaser/meta.yaml index a30476c50..3d8d0f5ed 100644 --- a/conda/artiq-kc705-phaser/meta.yaml +++ b/conda/artiq-kc705-phaser/meta.yaml @@ -14,7 +14,7 @@ requirements: build: - migen 0.4 - misoc 0.4 - - jesd204b 0.1 + - jesd204b 0.2 - llvm-or1k - binutils-or1k-linux >=2.27 - rust-core-or1k From 342b9e977ee594d49cdb3c233c89bc796a391cc4 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 18 Nov 2016 15:46:59 +0100 Subject: [PATCH 093/157] phaser: cap phy data width to 64 temporarily --- artiq/gateware/rtio/phy/sawg.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/phy/sawg.py b/artiq/gateware/rtio/phy/sawg.py index 84094f5a2..5b15806e6 100644 --- a/artiq/gateware/rtio/phy/sawg.py +++ b/artiq/gateware/rtio/phy/sawg.py @@ -16,7 +16,8 @@ class Channel(_ChannelPHY): _ChannelPHY.__init__(self, *args, **kwargs) self.phys = [] for i in self.i: - rl = rtlink.Interface(rtlink.OInterface(len(i.payload))) + rl = rtlink.Interface(rtlink.OInterface( + min(64, len(i.payload)))) # FIXME self.comb += [ i.stb.eq(rl.o.stb), rl.o.busy.eq(~i.ack), From 641f07119f8c7410731e4f08d1923161580978fb Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 18 Nov 2016 17:08:33 +0100 Subject: [PATCH 094/157] runtime: support rtio data wider than 64 bit --- artiq/coredevice/rtio.py | 8 +++++++- artiq/runtime/rtio.c | 28 ++++++++++++++++++++++++---- artiq/runtime/rtio.h | 9 +++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/rtio.py b/artiq/coredevice/rtio.py index f4d0e2c82..de9954fc1 100644 --- a/artiq/coredevice/rtio.py +++ b/artiq/coredevice/rtio.py @@ -1,5 +1,5 @@ from artiq.language.core import syscall -from artiq.language.types import TInt64, TInt32, TNone +from artiq.language.types import TInt64, TInt32, TNone, TList @syscall(flags={"nowrite"}) @@ -8,6 +8,12 @@ def rtio_output(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32 raise NotImplementedError("syscall not simulated") +@syscall(flags={"nowrite"}) +def rtio_output_list(time_mu: TInt64, channel: TInt32, addr: TInt32, + data: TList(TInt32)) -> TNone: + raise NotImplementedError("syscall not simulated") + + @syscall(flags={"nowrite"}) def rtio_input_timestamp(timeout_mu: TInt64, channel: TInt32) -> TInt64: raise NotImplementedError("syscall not simulated") diff --git a/artiq/runtime/rtio.c b/artiq/runtime/rtio.c index ac5168224..9dd47212e 100644 --- a/artiq/runtime/rtio.c +++ b/artiq/runtime/rtio.c @@ -58,7 +58,27 @@ void rtio_output(long long int timestamp, int channel, unsigned int addr, #ifdef CSR_RTIO_O_ADDRESS_ADDR rtio_o_address_write(addr); #endif - rtio_o_data_write(data); + MMPTR(CSR_RTIO_O_DATA_ADDR) = data; + rtio_o_we_write(1); + status = rtio_o_status_read(); + if(status) + rtio_process_exceptional_status(timestamp, channel, status); +} + + +void rtio_output_list(long long int timestamp, int channel, + unsigned int addr, struct artiq_list data) +{ + int status, i; + volatile unsigned int *p = &MMPTR(CSR_RTIO_O_DATA_ADDR); + + rtio_chan_sel_write(channel); + rtio_o_timestamp_write(timestamp); +#ifdef CSR_RTIO_O_ADDRESS_ADDR + rtio_o_address_write(addr); +#endif + for(i=0;i Date: Fri, 18 Nov 2016 17:08:44 +0100 Subject: [PATCH 095/157] Revert "phaser: cap phy data width to 64 temporarily" This reverts commit 342b9e977ee594d49cdb3c233c89bc796a391cc4. --- artiq/gateware/rtio/phy/sawg.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/phy/sawg.py b/artiq/gateware/rtio/phy/sawg.py index 5b15806e6..84094f5a2 100644 --- a/artiq/gateware/rtio/phy/sawg.py +++ b/artiq/gateware/rtio/phy/sawg.py @@ -16,8 +16,7 @@ class Channel(_ChannelPHY): _ChannelPHY.__init__(self, *args, **kwargs) self.phys = [] for i in self.i: - rl = rtlink.Interface(rtlink.OInterface( - min(64, len(i.payload)))) # FIXME + rl = rtlink.Interface(rtlink.OInterface(len(i.payload))) self.comb += [ i.stb.eq(rl.o.stb), rl.o.busy.eq(~i.ack), From 0ee47e77aee35bcb4589f3531153bdeff549174c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 18 Nov 2016 17:24:11 +0100 Subject: [PATCH 096/157] phaser: fix widths --- artiq/gateware/dsp/sawg.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 2615d2018..ac66df271 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -58,7 +58,7 @@ class SplineParallelDUC(ParallelDDS): self.submodules += p, f self.ce = Signal(reset=1) self.clr = Signal() - super().__init__(widths._replace(p=len(self.f.a0), f=len(self.f.a0)), + super().__init__(widths._replace(p=len(self.p.a0), f=len(self.f.a0)), **kwargs) self.latency += f.latency @@ -146,7 +146,8 @@ class Channel(Module, SatAddMixin): self.submodules.a1 = a1 = SplineParallelDDS(widths, orders) self.submodules.a2 = a2 = SplineParallelDDS(widths, orders) self.submodules.b = b = SplineParallelDUC( - widths, orders, parallelism=parallelism, a_delay=-a1.latency) + widths._replace(a=len(a1.xo[0])), orders, + parallelism=parallelism, a_delay=-a1.latency) cfg = Config(widths.a) u = Spline(width=widths.a, order=orders.a) du = Delay(widths.a, a1.latency + b.latency - u.latency) From b714137f76c3309bbfae04b9686c8cdb5dc82f4c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 19 Nov 2016 13:05:29 +0100 Subject: [PATCH 097/157] phaser: 150 MHz rtio/jesd clock --- artiq/examples/phaser/device_db.pyon | 10 +++++----- artiq/gateware/targets/kc705.py | 23 +++++++++-------------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/artiq/examples/phaser/device_db.pyon b/artiq/examples/phaser/device_db.pyon index c9bfe06f5..9858fc093 100644 --- a/artiq/examples/phaser/device_db.pyon +++ b/artiq/examples/phaser/device_db.pyon @@ -12,7 +12,7 @@ "module": "artiq.coredevice.core", "class": "Core", "arguments": { - "ref_period": 1e-9, + "ref_period": 5/6, "external_clock": True } }, @@ -54,24 +54,24 @@ "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 4, "parallelism": 4} + "arguments": {"channel_base": 4, "parallelism": 2} }, "sawg1": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 7, "parallelism": 4} + "arguments": {"channel_base": 7, "parallelism": 2} }, "sawg2": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 10, "parallelism": 4} + "arguments": {"channel_base": 10, "parallelism": 2} }, "sawg3": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 13, "parallelism": 4} + "arguments": {"channel_base": 13, "parallelism": 2} } } diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index b96450816..a9aa55a6a 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -397,13 +397,13 @@ class _PhaserCRG(Module, AutoCSR): p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, p_REF_JITTER1=0.01, p_REF_JITTER2=0.01, - p_CLKIN1_PERIOD=4.0, p_CLKIN2_PERIOD=4.0, + 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 @ 1GHz when using 250MHz input - p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=2, + # 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, @@ -419,7 +419,7 @@ class _PhaserCRG(Module, AutoCSR): self._pll_locked.status) ] self.cd_rtio.clk.attr.add("keep") - platform.add_period_constraint(self.cd_rtio.clk, 8.) + platform.add_period_constraint(self.cd_rtio.clk, 20/3) class AD9154JESD(Module, AutoCSR): @@ -427,9 +427,9 @@ class AD9154JESD(Module, AutoCSR): 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 = 10e9 - refclk_freq = 250e6 - fabric_freq = 250*1000*1000 + linerate = 6e9 + refclk_freq = 150e6 + fabric_freq = 150*1000*1000 sync_pads = platform.request("ad9154_sync") self.jsync = Signal() @@ -494,16 +494,11 @@ class AD9154(Module, AutoCSR): self.submodules.jesd = AD9154JESD(platform) - self.sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] + self.sawgs = [sawg.Channel(width=16, parallelism=2) for i in range(4)] self.submodules += self.sawgs - x = Signal() - y = Signal() - z = Signal() - self.sync.jesd += x.eq(~x), z.eq(x == y) - self.sync.rio_phy += y.eq(x) for conv, ch in zip(self.jesd.core.sink.flatten(), self.sawgs): - self.sync.jesd += conv.eq(Mux(z, Cat(ch.o[:2]), Cat(ch.o[2:]))) + self.sync.jesd += conv.eq(Cat(ch.o)) class Phaser(MiniSoC, AMPSoC): From 97a54046e85f0c377eef6c17cd23ab00e2c577a0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 19 Nov 2016 14:16:06 +0100 Subject: [PATCH 098/157] rtio: auto clear output event data and address This is to support channels where variable length event data is well-defined through zero-padding. E.g. in the case of `Spline` zero-padding of events naturally corresponds to low-order knots. Use timestamp change as trigger. This assumes that writes to the timestamp register always precede address and data writes. It does not break support for ganged writes of the same event timestamp and data/address to multiple channels or channel-addresses. --- artiq/gateware/rtio/core.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index a248632da..4d5624684 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -334,9 +334,9 @@ class _KernelCSRs(AutoCSR): self.chan_sel = CSRStorage(chan_sel_width) if data_width: - self.o_data = CSRStorage(data_width) + self.o_data = CSRStorage(data_width, write_from_dev=True) if address_width: - self.o_address = CSRStorage(address_width) + self.o_address = CSRStorage(address_width, write_from_dev=True) self.o_timestamp = CSRStorage(full_ts_width) self.o_we = CSR() self.o_status = CSRStatus(5) @@ -498,5 +498,13 @@ class RTIO(Module): << fine_ts_width) ) + # Auto clear/zero pad event data + self.comb += [ + self.kcsrs.o_data.dat_w.eq(0), + self.kcsrs.o_data.we.eq(self.kcsrs.o_timestamp.re), + self.kcsrs.o_address.dat_w.eq(0), + self.kcsrs.o_address.we.eq(self.kcsrs.o_timestamp.re), + ] + def get_csrs(self): return self.kcsrs.get_csrs() From e53d0bcd5bed3979bfcadf7413be4c987d987751 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 19 Nov 2016 15:40:42 +0100 Subject: [PATCH 099/157] dsp: add limits support to SatAddMixin --- artiq/gateware/dsp/tools.py | 40 ++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/artiq/gateware/dsp/tools.py b/artiq/gateware/dsp/tools.py index 5ae78bd8c..b413fae3f 100644 --- a/artiq/gateware/dsp/tools.py +++ b/artiq/gateware/dsp/tools.py @@ -29,21 +29,33 @@ def eqh(a, b): class SatAddMixin: - def sat_add(self, a): + """Signed saturating addition mixin""" + def sat_add(self, *a, limits=None, clipped=None): a = list(a) # assert all(value_bits_sign(ai)[1] for ai in a) - n = max(len(ai) for ai in a) - o = log2_int(len(a), need_pow2=False) - s = Signal((n + o, True)) - s0 = Signal((n, True)) - z = Signal((1, True)) + length = max(len(ai) for ai in a) + carry = log2_int(len(a), need_pow2=False) + full = Signal((length + carry, True)) + limited = Signal((length, True)) + clip = Signal(2) + if clipped is not None: + clipped.eq(clip) self.comb += [ - s.eq(reduce(add, a, z)), - s0[-1].eq(s[-1]), - If(s[-o-1:] == Replicate(s[-1], o + 1), - s0[:-1].eq(s[:n-1]), - ).Else( - s0[:-1].eq(Replicate(~s[-1], n - 1)), - ) + full.eq(reduce(add, a)), ] - return s0 + if limits is None: + self.comb += [ + If(full[-1-carry:] == Replicate(full[-1], carry + 1), + limited.eq(full), + clip.eq(0), + ).Else( + limited.eq(Cat(Replicate(~full[-1], length - 1), full[-1])), + clip.eq(Cat(full[-1], ~full[-1])), + ) + ] + else: + self.comb += [ + clip.eq(Cat(full < limits[0], full > limits[1])), + limited.eq(Array([full, limits[0], limits[1], 0])[clip]), + ] + return limited From 04813ea29bc70717c12a43764628d47946b2193c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 19 Nov 2016 15:53:33 +0100 Subject: [PATCH 100/157] sawg: wir up limiting, saturating addition --- artiq/gateware/dsp/sawg.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index ac66df271..28549611c 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -104,10 +104,11 @@ class Config(Module): def __init__(self, width): self.clr = Signal(4, reset=0b1111) self.iq_en = Signal(2, reset=0b01) - self.limit = [[Signal((width, True), reset=-(1 << width - 1)), + self.limits = [[Signal((width, True), reset=-(1 << width - 1)), Signal((width, True), reset=(1 << width - 1) - 1)] - for i in range(2)] - self.i = Endpoint([("addr", bits_for(4 + 2*len(self.limit))), + for i in range(3)] + self.clipped = [Signal(2) for i in range(3)] # TODO + self.i = Endpoint([("addr", bits_for(4 + len(self.limits))), ("data", 16)]) self.ce = Signal() @@ -118,7 +119,7 @@ class Config(Module): pad = Signal() reg = Array([Cat(div, n), self.clr, self.iq_en, pad] + - sum(self.limit, [])) + [Cat(*l) for l in self.limits]) self.comb += [ self.i.ack.eq(1), @@ -161,7 +162,7 @@ class Channel(Module, SatAddMixin): self.widths = widths self.orders = orders self.parallelism = parallelism - self.latency = a1.latency + b.latency + 1 + self.latency = a1.latency + b.latency + 2 self.cordic_gain = a1.gain*b.gain ### @@ -172,17 +173,22 @@ class Channel(Module, SatAddMixin): b.ce.eq(cfg.ce), u.o.ack.eq(cfg.ce), Cat(a1.clr, a2.clr, b.clr).eq(cfg.clr), - b.i.x.eq(self.sat_add([a1.xo[0], a2.xo[0]])), - b.i.y.eq(self.sat_add([a1.yo[0], a2.yo[0]])), + ] + self.sync += [ + b.i.x.eq(self.sat_add(a1.xo[0], a2.xo[0], + limits=cfg.limits[0], + clipped=cfg.clipped[0])), + b.i.y.eq(self.sat_add(a1.yo[0], a2.yo[0], + limits=cfg.limits[1], + clipped=cfg.clipped[1])), eqh(du.i, u.o.a0), ] # wire up outputs and q_{i,o} exchange for o, x, y in zip(self.o, b.xo, self.y_in): self.sync += [ - o.eq(self.sat_add([ - du.o, - Mux(cfg.iq_en[0], x, 0), - Mux(cfg.iq_en[1], y, 0)])), + o.eq(self.sat_add( + du.o, Mux(cfg.iq_en[0], x, 0), Mux(cfg.iq_en[1], y, 0), + limits=cfg.limits[2], clipped=cfg.clipped[2])), ] def connect_y(self, buddy): From 12e39a64cfa37c75f6a9f40fef69d6dc83425a53 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 19 Nov 2016 17:07:07 +0100 Subject: [PATCH 101/157] sawg: reduce f0 oscillator width to 32 --- artiq/gateware/dsp/sawg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 28549611c..0d038e4fc 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -147,7 +147,7 @@ class Channel(Module, SatAddMixin): self.submodules.a1 = a1 = SplineParallelDDS(widths, orders) self.submodules.a2 = a2 = SplineParallelDDS(widths, orders) self.submodules.b = b = SplineParallelDUC( - widths._replace(a=len(a1.xo[0])), orders, + widths._replace(a=len(a1.xo[0]), f=widths.f - width), orders, parallelism=parallelism, a_delay=-a1.latency) cfg = Config(widths.a) u = Spline(width=widths.a, order=orders.a) From 74e5013fe595a72d639e481d8c48dfc836f3db6c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 20 Nov 2016 16:39:22 +0100 Subject: [PATCH 102/157] sawg: fix b delay width --- artiq/gateware/dsp/sawg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 0d038e4fc..9ff89d72e 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -151,7 +151,7 @@ class Channel(Module, SatAddMixin): parallelism=parallelism, a_delay=-a1.latency) cfg = Config(widths.a) u = Spline(width=widths.a, order=orders.a) - du = Delay(widths.a, a1.latency + b.latency - u.latency) + du = Delay(width, a1.latency + b.latency - u.latency) self.submodules += cfg, u, du self.u = u.tri(widths.t) self.i = [cfg.i, self.u, a1.a, a1.f, a1.p, a2.a, a2.f, a2.p, b.f, b.p] From 9221a275cb8285509922bf7d2dcbd54a438b66d8 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 20 Nov 2016 16:39:53 +0100 Subject: [PATCH 103/157] sawg: kernel support (wip) --- artiq/coredevice/sawg.py | 188 ++++++++++++++++++--------- artiq/examples/phaser/device_db.pyon | 8 +- 2 files changed, 131 insertions(+), 65 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index f6f90f973..3858527d6 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -1,73 +1,139 @@ -from artiq.language.core import kernel, now_mu -from artiq.coredevice.rtio import rtio_output -from artiq.language.types import TInt32, TFloat +from artiq.language.core import kernel, now_mu, portable +from artiq.coredevice.rtio import rtio_output, rtio_output_list +from artiq.language.types import TInt32, TInt64, TFloat, TList + + +class Spline: + kernel_invariants = {"channel", "core", "scale", "width", + "time_width", "time_scale"} + + def __init__(self, width, time_width, channel, core_device, scale=1.): + self.core = core_device + self.channel = channel + self.width = width + self.scale = (1 << width) / scale + self.time_width = time_width + self.time_scale = (1 << time_width) / core_device.coarse_ref_period + + @portable(flags=["fast-math"]) + def to_mu(self, value: TFloat) -> TInt32: + return int(round(value*self.scale)) + + @portable(flags=["fast-math"]) + def from_mu(self, value: TInt32) -> TFloat: + return value/self.scale + + @portable(flags=["fast-math"]) + def to_mu64(self, value: TFloat) -> TList(TInt32): + v = int(round(value*self.scale), width=64) + return [int(v >> 32, width=32), int(v, width=32)] + + @kernel + def set_mu(self, value: TInt32): + """Set spline value (machine units). + + :param value: Spline value in integer machine units. + """ + rtio_output(now_mu(), self.channel, 0, value) + + @kernel + def set(self, value: TFloat): + """Set spline value. + + :param value: Spline value relative to full-scale. + """ + rtio_output(now_mu(), self.channel, 0, self.to_mu(value)) + + @kernel + def set64(self, value: TFloat): + """Set spline value. + + :param value: Spline value relative to full-scale. + """ + rtio_output_list(now_mu(), self.channel, 0, self.to_mu64(value)) + + @kernel + def set_list_mu(self, value: TList(TInt32)): + """Set spline raw values. + + :param value: Spline packed raw values. + """ + rtio_output_list(now_mu(), self.channel, 0, value) + + @portable(flags=["fast-math"]) + def coeff_to_mu(self, value: TList(TFloat)) -> TList(TInt32): + l = len(value) + w = l*self.width + (l - 1)*l//2*self.time_width + v = [0] * ((w + 31)//32) + j = 0 + for i, vi in enumerate(value): + w = self.width + i*self.time_width + vi = int(round(vi*(self.scale*self.time_scale**i)), width=64) + for k in range(0, w, 16): + wi = (vi >> k) & 0xffff + v[j//2] += wi << (16 * ((j + 1)//2 - j//2)) + j += 1 + v.append(vi) + return v + + @kernel + def set_list(self, value: TList(TFloat)): + """Set spline coefficients. + + :param value: List of floating point spline knot coefficients, + lowest order (constant) coefficient first. + """ + self.set_list_mu(self.coeff_to_mu(value)) class SAWG: """Smart arbitrary waveform generator channel. + The channel is parametrized as: :: + + oscillators = exp(2j*pi*(frequency0*t + phase0))*( + amplitude1*exp(2j*pi*(frequency1*t + phase1)) + + amplitude2*exp(2j*pi*(frequency2*t + phase2)) + + output = (offset + + i_enable*Re(oscillators) + + q_enable*Im(buddy_oscillators)) + + Where: + * offset, amplitude1, amplitude1: in units of full scale + * phase0, phase1, phase2: in units of turns + * frequency0, frequency1, frequency2: in units of Hz :param channel_base: RTIO channel number of the first channel (amplitude). Frequency and Phase are then assumed to be successive channels. """ - kernel_invariants = {"amplitude_scale", "frequency_scale", "phase_scale", - "channel_base", "core"} + kernel_invariants = {"channel_base", "core", + "amplitude1", "frequency1", "phase1", + "amplitude2", "frequency2", "phase2" + "frequency0", "phase0", "offset"} - def __init__(self, dmgr, channel_base, parallelism=4, core_device="core"): + def __init__(self, dmgr, channel_base, parallelism, core_device="core"): self.core = dmgr.get(core_device) self.channel_base = channel_base + width = 16 + time_width = 16 cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain - a_width = 16 - f_width = 32 - p_width = 16 - self.amplitude_scale = (1 << a_width) / 2 / cordic_gain - self.phase_scale = 1 << p_width - self.frequency_scale = ((1 << f_width) * self.core.coarse_ref_period / - parallelism) - - @kernel - def set_amplitude_mu(self, amplitude: TInt32): - """Set DDS amplitude (machine units). - - :param amplitude: DDS amplitude in machine units. - """ - rtio_output(now_mu(), self.channel_base, 0, amplitude) - - @kernel(flags=["fast-math"]) - def set_amplitude(self, amplitude: TFloat): - """Set DDS amplitude. - - :param amplitude: DDS amplitude relative to full-scale. - """ - self.set_amplitude_mu(int(round(amplitude*self.amplitude_scale))) - - @kernel - def set_frequency_mu(self, frequency: TInt32): - """Set DDS frequency (machine units). - - :param frequency: DDS frequency in machine units. - """ - rtio_output(now_mu(), self.channel_base + 1, 0, frequency) - - @kernel(flags=["fast-math"]) - def set_frequency(self, frequency: TFloat): - """Set DDS frequency. - - :param frequency: DDS frequency in Hz. - """ - self.set_frequency_mu(int(round(frequency*self.frequency_scale))) - - @kernel - def set_phase_mu(self, phase: TInt32): - """Set DDS phase (machine units). - - :param phase: DDS phase in machine units. - """ - rtio_output(now_mu(), self.channel_base + 2, 0, phase) - - @kernel(flags=["fast-math"]) - def set_phase(self, phase: TFloat): - """Set DDS phase. - - :param phase: DDS phase relative in turns. - """ - self.set_phase_mu(int(round(phase*self.phase_scale))) + # cfg: channel_base + self.offset = Spline(width, time_width, channel_base + 1, + self.core, 2) + self.amplitude1 = Spline(width, time_width, channel_base + 2, + self.core, 2*cordic_gain**2) + self.frequency1 = Spline(3*width, time_width, channel_base + 3, + self.core, self.core.coarse_ref_period) + self.phase1 = Spline(width, time_width, channel_base + 4, + self.core, 1.) + self.amplitude2 = Spline(width, time_width, channel_base + 5, + self.core, 2*cordic_gain**2) + self.frequency2 = Spline(3*width, time_width, channel_base + 6, + self.core, self.core.coarse_ref_period) + self.phase2 = Spline(width, time_width, channel_base + 7, + self.core, 1.) + self.frequency0 = Spline(2*width, time_width, channel_base + 8, + self.core, + parallelism/self.core.coarse_ref_period) + self.phase0 = Spline(width, time_width, channel_base + 9, + self.core, 1.) diff --git a/artiq/examples/phaser/device_db.pyon b/artiq/examples/phaser/device_db.pyon index 9858fc093..1bd1beb74 100644 --- a/artiq/examples/phaser/device_db.pyon +++ b/artiq/examples/phaser/device_db.pyon @@ -12,7 +12,7 @@ "module": "artiq.coredevice.core", "class": "Core", "arguments": { - "ref_period": 5/6, + "ref_period": 5e-9/6, "external_clock": True } }, @@ -60,18 +60,18 @@ "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 7, "parallelism": 2} + "arguments": {"channel_base": 14, "parallelism": 2} }, "sawg2": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 10, "parallelism": 2} + "arguments": {"channel_base": 24, "parallelism": 2} }, "sawg3": { "type": "local", "module": "artiq.coredevice.sawg", "class": "SAWG", - "arguments": {"channel_base": 13, "parallelism": 2} + "arguments": {"channel_base": 34, "parallelism": 2} } } From 174c4be218f16ebfe5cf2b53004f271fbf8f3dbd Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 21 Nov 2016 09:57:33 +0100 Subject: [PATCH 104/157] phaser: false paths sys<->{jesd,phy.tx} --- artiq/gateware/targets/kc705.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index a9aa55a6a..15d0d652c 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -451,7 +451,7 @@ class AD9154JESD(Module, AutoCSR): qpll = GTXQuadPLL(refclk, refclk_freq, linerate) self.submodules += qpll - phys = [] + self.phys = [] for i in range(4): phy = JESD204BPhyTX( qpll, platform.request("ad9154_jesd", i), fabric_freq) @@ -459,9 +459,9 @@ class AD9154JESD(Module, AutoCSR): 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) - phys.append(phy) + self.phys.append(phy) to_jesd = ClockDomainsRenamer("jesd") - self.submodules.core = to_jesd(JESD204BCoreTX(phys, settings, + self.submodules.core = to_jesd(JESD204BCoreTX(self.phys, settings, converter_data_width=32)) self.submodules.control = to_jesd(JESD204BCoreTXControl(self.core)) @@ -595,8 +595,12 @@ class Phaser(MiniSoC, AMPSoC): 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) + 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(): From 2f838e35129c3eb85d01782c63001758061d2fe3 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 21 Nov 2016 12:15:26 +0100 Subject: [PATCH 105/157] rtio: fix i_data/o_data csr endianess --- artiq/runtime/rtio.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/artiq/runtime/rtio.c b/artiq/runtime/rtio.c index 9dd47212e..a259ab0c8 100644 --- a/artiq/runtime/rtio.c +++ b/artiq/runtime/rtio.c @@ -58,7 +58,7 @@ void rtio_output(long long int timestamp, int channel, unsigned int addr, #ifdef CSR_RTIO_O_ADDRESS_ADDR rtio_o_address_write(addr); #endif - MMPTR(CSR_RTIO_O_DATA_ADDR) = data; + MMPTR(CSR_RTIO_O_DATA_ADDR + CSR_RTIO_O_DATA_SIZE - 1) = data; rtio_o_we_write(1); status = rtio_o_status_read(); if(status) @@ -70,7 +70,8 @@ void rtio_output_list(long long int timestamp, int channel, unsigned int addr, struct artiq_list data) { int status, i; - volatile unsigned int *p = &MMPTR(CSR_RTIO_O_DATA_ADDR); + volatile unsigned int *p = &MMPTR( + CSR_RTIO_O_DATA_ADDR + CSR_RTIO_O_DATA_SIZE - 1); rtio_chan_sel_write(channel); rtio_o_timestamp_write(timestamp); @@ -78,7 +79,7 @@ void rtio_output_list(long long int timestamp, int channel, rtio_o_address_write(addr); #endif for(i=0;i Date: Mon, 21 Nov 2016 12:35:57 +0100 Subject: [PATCH 106/157] sawg: unittest data format --- artiq/coredevice/sawg.py | 3 +- artiq/test/gateware/test_sawg_fe.py | 141 ++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 artiq/test/gateware/test_sawg_fe.py diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 3858527d6..49d018843 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -26,7 +26,7 @@ class Spline: @portable(flags=["fast-math"]) def to_mu64(self, value: TFloat) -> TList(TInt32): v = int(round(value*self.scale), width=64) - return [int(v >> 32, width=32), int(v, width=32)] + return [int(v, width=32), int(v >> 32, width=32)] @kernel def set_mu(self, value: TInt32): @@ -73,7 +73,6 @@ class Spline: wi = (vi >> k) & 0xffff v[j//2] += wi << (16 * ((j + 1)//2 - j//2)) j += 1 - v.append(vi) return v @kernel diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py new file mode 100644 index 000000000..325709340 --- /dev/null +++ b/artiq/test/gateware/test_sawg_fe.py @@ -0,0 +1,141 @@ +import unittest +import numpy as np + +import migen as mg + +from artiq.coredevice import sawg +from artiq.language import delay_mu, core as core_language +from artiq.gateware.rtio.phy.sawg import Channel +from artiq.sim import devices as sim_devices, time as sim_time + + +class RTIOManager: + def __init__(self): + self.outputs = [] + + def rtio_output(self, now, channel, addr, data): + self.outputs.append((now, channel, addr, data)) + + def rtio_output_list(self, *args, **kwargs): + self.rtio_output(*args, **kwargs) + + def int(self, value, width=32): + if width == 32: + return np.int32(value) + elif width == 64: + return np.int64(value) + else: + raise ValueError(width) + + def patch(self, mod): + assert not getattr(mod, "_saved", None) + mod._saved = {} + for name in "rtio_output rtio_output_list int".split(): + mod._saved[name] = getattr(mod, name, None) + setattr(mod, name, getattr(self, name)) + + def unpatch(self, mod): + mod.__dict__.update(mod._saved) + del mod._saved + + +class SAWGTest(unittest.TestCase): + def setUp(self): + core_language.set_time_manager(sim_time.Manager()) + self.rtio_manager = RTIOManager() + self.rtio_manager.patch(sawg) + self.core = sim_devices.Core({}) + self.core.coarse_ref_period = 8 + self.channel = mg.ClockDomainsRenamer({"rio_phy": "sys"})( + Channel(width=16, parallelism=4)) + self.driver = sawg.SAWG({"core": self.core}, channel_base=0, + parallelism=self.channel.parallelism) + + def tearDown(self): + self.rtio_manager.unpatch(sawg) + + def test_instantiate(self): + pass + + def test_make_events(self): + d = self.driver + d.offset.set(.9) + delay_mu(2*8) + d.frequency0.set64(.1) + delay_mu(2*8) + d.offset.set(0) + self.assertEqual( + self.rtio_manager.outputs, [ + (0, 1, 0, int(round( + (1 << self.driver.offset.width - 1)*.9))), + (2*8, 8, 0, [0, int(round( + (1 << self.driver.frequency0.width - 1) * + self.channel.parallelism*.1))]), + (4*8, 1, 0, 0), + ]) + + def run_channel(self, events): + def gen(dut, events): + c = 0 + for time, channel, address, data in events: + assert c <= time + while c < time: + yield + c += 1 + for phy in dut.phys: + yield phy.rtlink.o.stb.eq(0) + rt = dut.phys[channel].rtlink.o + if isinstance(data, list): + data = sum(d << i*32 for i, d in enumerate(data)) + yield rt.data.eq(int(data)) + yield rt.stb.eq(1) + assert not (yield rt.busy) + + def log(dut, data, n): + for i in range(dut.latency): + yield + for i in range(n): + yield + data.append((yield from [(yield _) for _ in dut.o])) + + data = [] + mg.run_simulation(self.channel, [ + gen(self.channel, events), + log(self.channel, data, int(events[-1][0]//8) + 1)], + vcd_name="dds.vcd") + return sum(data, []) + + def test_channel(self): + self.test_make_events() + out = self.run_channel(self.rtio_manager.outputs) + print(out) + + def test_coeff(self): + import struct + for v in [-.1], [.1, -.01], [.1, .01, -.00001], \ + [.1, .01, .00001, -.000000001]: + ch = self.driver.offset + p = ch.coeff_to_mu(v) + t = ch.time_width + w = ch.width + p0 = [struct.pack("<" + "_hiqq"[(w + i*t)//16], + int(round(vi*ch.scale*ch.time_scale**i)) + )[:(w + i*t)//8] + for i, vi in enumerate(v)] + p0 = b"".join(p0) + if len(p0) % 4: + p0 += b"\x00"*(4 - len(p0) % 4) + p0 = list(struct.unpack("<" + "I"*((len(p0) + 3)//4), p0)) + with self.subTest(v): + self.assertEqual(p, p0) + + def test_linear(self): + d = self.driver + d.offset.set_list_mu([100, 10]) + delay_mu(10*8) + d.offset.set_list([0]) + delay_mu(1*8) + out = self.run_channel(self.rtio_manager.outputs) + self.assertEqual( + out, sum(([100 + i*10]*self.channel.parallelism + for i in range(11)), [])) From c73b1af7abcbb690a8c6c39aa7db84ac2c5f6e47 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 21 Nov 2016 13:16:44 +0100 Subject: [PATCH 107/157] coredevice/sawg: missing comma --- artiq/coredevice/sawg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 49d018843..d90eba9ed 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -107,7 +107,7 @@ class SAWG: """ kernel_invariants = {"channel_base", "core", "amplitude1", "frequency1", "phase1", - "amplitude2", "frequency2", "phase2" + "amplitude2", "frequency2", "phase2", "frequency0", "phase0", "offset"} def __init__(self, dmgr, channel_base, parallelism, core_device="core"): From b3e4a1df03c05e16c24c4ba2b3d55db3e81f3aab Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 21 Nov 2016 13:17:01 +0100 Subject: [PATCH 108/157] sawg: adapt basic example --- artiq/examples/phaser/repository/sawg.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/artiq/examples/phaser/repository/sawg.py b/artiq/examples/phaser/repository/sawg.py index e6749ce7d..8710a34d2 100644 --- a/artiq/examples/phaser/repository/sawg.py +++ b/artiq/examples/phaser/repository/sawg.py @@ -15,18 +15,18 @@ class SAWGTest(EnvExperiment): def run(self): self.core.break_realtime() - self.sawg0.set_amplitude(.1) - self.sawg0.set_frequency(10*MHz) - self.sawg0.set_phase(0.) - self.sawg1.set_amplitude(-.9) - self.sawg1.set_frequency(20*MHz) - self.sawg1.set_phase(0.) - self.sawg2.set_amplitude(.5) - self.sawg2.set_frequency(30*MHz) - self.sawg2.set_phase(0.) - self.sawg3.set_amplitude(.5) - self.sawg3.set_frequency(30*MHz) - self.sawg3.set_phase(.5) + self.sawg0.amplitude1.set(.1) + self.sawg0.frequency0.set(10*MHz) + self.sawg0.phase0.set(0.) + self.sawg1.amplitude1.set(-.9) + self.sawg1.frequency0.set(20*MHz) + self.sawg1.phase0.set(0.) + self.sawg2.amplitude1.set(.5) + self.sawg2.frequency0.set(30*MHz) + self.sawg2.phase0.set(0.) + self.sawg3.amplitude1.set(.5) + self.sawg3.frequency0.set(30*MHz) + self.sawg3.phase0.set(.5) for i in range(10): self.led.pulse(100*ms) From ad264ac07093e0098574e72adbc1cef79e99ac75 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 21 Nov 2016 16:58:07 +0100 Subject: [PATCH 109/157] phaser: 300 MHz sample rate clock/dac --- README_PHASER.rst | 12 +++++----- artiq/examples/phaser/repository/dac_setup.py | 10 ++++----- artiq/examples/phaser/startup_kernel.py | 22 ++++++++----------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/README_PHASER.rst b/README_PHASER.rst index 617519ea8..723d22601 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -7,16 +7,16 @@ Ultimately it will be the basis for the ARTIQ Sayma Smart Arbitrary Waveform Gen *Features*: -* 4 channels -* 500 MHz data rate per channel (KC705 limitation) -* 4x interpolation to 2 GHz DAC sample rate +* up to 4 channels +* up to 500 MHz data rate per channel (KC705 limitation) +* up to 8x interpolation to 2.4 GHz DAC sample rate * Real-time control over amplitude, frequency, phase of each channel through ARTIQ RTIO commands * Full configurability of the AD9154 and AD9516 through SPI with ARTIQ kernel support * All SPI registers and register bits exposed as human readable names * Parametrized JESD204B core (also capable of operation with eight lanes) * The code can be reconfigured. Possible example configurations are: support 2 channels at 1 GHz datarate, support 4 channels at 300 MHz data rate, no interpolation, and using mix mode to stress the second and third Nyquist zones (150-300 MHz and 300-450 MHz). -The hardware required to use the ARTIQ phaser branch is a KC705 with an AD9154-FMC-EBZ plugged into the HPC connector and a low-noise 2 GHz reference clock. +The hardware required to use the ARTIQ phaser branch is a KC705 with an AD9154-FMC-EBZ plugged into the HPC connector and a low-noise sample rate reference clock. This work was supported by the Army Research Lab. @@ -90,7 +90,7 @@ Setup * Refer to the ARTIQ documentation to configure an IP address and other settings for the transmitter device. If the board was running stock ARTIQ before, the settings will be kept. -* A 2 GHz of roughly 10 dBm (0.2 to 3.4 V peak-to-peak into 50 Ohm) must be connected to the AD9154-FMC-EBZ J1. +* A 300 MHz clock of roughly 10 dBm (0.2 to 3.4 V peak-to-peak into 50 Ohm) must be connected to the AD9154-FMC-EBZ J1. The external RTIO clock, DAC deviceclock, FPGA deviceclock, and SYSREF are derived from this signal. * An example device database, several status and test scripts are provided in ``artiq/examples/phaser/``. :: @@ -113,7 +113,7 @@ Usage * Run ``artiq_run repository/demo.py`` for an example that exercises several different use cases of synchronized phase, amplitude, and frequency updates. for an example that exercises several different use cases of synchronized phase, amplitude, and frequency updates. * Implement your own experiments using the SAWG channels. -* Verify clock stability between the 2 GHz reference clock and the DAC outputs. +* Verify clock stability between the sample rate reference clock and the DAC outputs. * Changes to the AD9154 configuration can also be performed at runtime in experiments. See the example ``dac_setup.py``. This can e.g. be used to enable and evaluate mix mode without having to change any other code (bitstream/bios/runtime/startup_kernel). diff --git a/artiq/examples/phaser/repository/dac_setup.py b/artiq/examples/phaser/repository/dac_setup.py index ed9a2da76..13b575045 100644 --- a/artiq/examples/phaser/repository/dac_setup.py +++ b/artiq/examples/phaser/repository/dac_setup.py @@ -19,10 +19,10 @@ ts = JESD204BTransportSettings( ) jesd_settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) jesd_checksum = jesd_settings.get_configuration_checksum() -# external clk=2000MHz -# pclock=250MHz -# deviceclock_fpga=250MHz -# deviceclock_dac=2000MHz +# external clk=300MHz +# pclock=150MHz +# deviceclock_fpga=150MHz +# deviceclock_dac=300MHz class DACSetup(EnvExperiment): @@ -123,7 +123,7 @@ class DACSetup(EnvExperiment): self.ad9154.dac_write(AD9154_SPI_PAGEINDX, 0x3) # A and B dual - self.ad9154.dac_write(AD9154_INTERP_MODE, 3) # 4x + self.ad9154.dac_write(AD9154_INTERP_MODE, 0) # 1x 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_DATAPATH_CTRL, diff --git a/artiq/examples/phaser/startup_kernel.py b/artiq/examples/phaser/startup_kernel.py index b611eef1a..3fb678ab4 100644 --- a/artiq/examples/phaser/startup_kernel.py +++ b/artiq/examples/phaser/startup_kernel.py @@ -28,10 +28,10 @@ class StartupKernel(EnvExperiment): if self.ad9154.clock_read(AD9516_PART_ID) != 0x41: raise ValueError("AD9516 not found") - # use clk input, dclk=clk/4 + # use clk input, dclk=clk/2 self.ad9154.clock_write(AD9516_PFD_AND_CHARGE_PUMP, 1*AD9516_PLL_POWER_DOWN | 0*AD9516_CHARGE_PUMP_MODE) - self.ad9154.clock_write(AD9516_VCO_DIVIDER, 2) + self.ad9154.clock_write(AD9516_VCO_DIVIDER, 0) self.ad9154.clock_write(AD9516_INPUT_CLKS, 0*AD9516_SELECT_VCO_OR_CLK | 0*AD9516_BYPASS_VCO_DIVIDER) @@ -47,25 +47,21 @@ class StartupKernel(EnvExperiment): self.ad9154.clock_write(AD9516_OUT1, 0*AD9516_OUT1_POWER_DOWN | 2*AD9516_OUT1_LVPECLDIFFERENTIAL_VOLTAGE) - # FPGA deviceclk, dclk/2 - self.ad9154.clock_write(AD9516_DIVIDER_4_3, AD9516_DIVIDER_4_BYPASS_2) - self.ad9154.clock_write(AD9516_DIVIDER_4_0, - (2//2-1)*AD9516_DIVIDER_0_HIGH_CYCLES | - (2//2-1)*AD9516_DIVIDER_0_LOW_CYCLES) + # FPGA deviceclk, dclk/1 + self.ad9154.clock_write(AD9516_DIVIDER_4_3, 0*AD9516_DIVIDER_4_NOSYNC | + 1*AD9516_DIVIDER_4_BYPASS_1 | 1*AD9516_DIVIDER_4_BYPASS_2) 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 | 2*AD9516_OUT9_LVDS_CMOS_OUTPUT_POLARITY | 0*AD9516_OUT9_SELECT_LVDS_CMOS) - # 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 | - (32//2-1)*AD9516_DIVIDER_3_LOW_CYCLES_1) + # sysref f_data*S/(K*F), dclk/16 + self.ad9154.clock_write(AD9516_DIVIDER_3_0, (16//2-1)*AD9516_DIVIDER_3_HIGH_CYCLES_1 | + (16//2-1)*AD9516_DIVIDER_3_LOW_CYCLES_1) self.ad9154.clock_write(AD9516_DIVIDER_3_1, 0*AD9516_DIVIDER_3_PHASE_OFFSET_1 | 0*AD9516_DIVIDER_3_PHASE_OFFSET_2) - self.ad9154.clock_write(AD9516_DIVIDER_3_2, (2//2-1)*AD9516_DIVIDER_3_HIGH_CYCLES_2 | - (2//2-1)*AD9516_DIVIDER_3_LOW_CYCLES_2) self.ad9154.clock_write(AD9516_DIVIDER_3_3, 0*AD9516_DIVIDER_3_NOSYNC | - 0*AD9516_DIVIDER_3_BYPASS_1 | 0*AD9516_DIVIDER_3_BYPASS_2) + 0*AD9516_DIVIDER_3_BYPASS_1 | 1*AD9516_DIVIDER_3_BYPASS_2) self.ad9154.clock_write(AD9516_DIVIDER_3_4, 0*AD9516_DIVIDER_3_DCCOFF) self.ad9154.clock_write(AD9516_OUT6, 1*AD9516_OUT6_LVDS_OUTPUT_CURRENT | 2*AD9516_OUT6_LVDS_CMOS_OUTPUT_POLARITY | From 5e900cf42a8211b9b127c63b062ac8f5f8f38816 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 21 Nov 2016 23:12:16 +0100 Subject: [PATCH 110/157] runtime.rs: wide rtio data --- artiq/runtime.rs/libksupport/api.rs | 1 + artiq/runtime.rs/libksupport/rtio.rs | 45 +++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/artiq/runtime.rs/libksupport/api.rs b/artiq/runtime.rs/libksupport/api.rs index 3eb28235e..0f9a96fb3 100644 --- a/artiq/runtime.rs/libksupport/api.rs +++ b/artiq/runtime.rs/libksupport/api.rs @@ -102,6 +102,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(rtio_get_counter = ::rtio::get_counter), api!(rtio_log), api!(rtio_output = ::rtio::output), + api!(rtio_output_list = ::rtio::output_list), api!(rtio_input_timestamp = ::rtio::input_timestamp), api!(rtio_input_data = ::rtio::input_data), diff --git a/artiq/runtime.rs/libksupport/rtio.rs b/artiq/runtime.rs/libksupport/rtio.rs index 107583da4..139e51f11 100644 --- a/artiq/runtime.rs/libksupport/rtio.rs +++ b/artiq/runtime.rs/libksupport/rtio.rs @@ -1,4 +1,6 @@ use board::csr; +use core::ptr::{read_volatile, write_volatile}; +use core::slice; const RTIO_O_STATUS_FULL: u32 = 1; const RTIO_O_STATUS_UNDERFLOW: u32 = 2; @@ -23,6 +25,21 @@ pub extern fn get_counter() -> i64 { } } +#[inline(always)] +pub unsafe fn rtio_o_data_write(w: u32) { + write_volatile( + csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1) as isize), + w); +} + +#[inline(always)] +pub unsafe fn rtio_i_data_read() -> u32 { + read_volatile( + csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1) as isize) + ) +} + + #[inline(never)] unsafe fn process_exceptional_status(timestamp: i64, channel: u32, status: u32) { if status & RTIO_O_STATUS_FULL != 0 { @@ -59,7 +76,27 @@ pub extern fn output(timestamp: i64, channel: u32, addr: u32, data: u32) { csr::rtio::chan_sel_write(channel); csr::rtio::o_timestamp_write(timestamp as u64); csr::rtio::o_address_write(addr); - csr::rtio::o_data_write(data); + rtio_o_data_write(data); + csr::rtio::o_we_write(1); + let status = csr::rtio::o_status_read(); + if status != 0 { + process_exceptional_status(timestamp, channel, status); + } + } +} + +pub extern fn output_list(timestamp: i64, channel: u32, addr: u32, + &(len, ptr): &(usize, *const u32)) { + unsafe { + csr::rtio::chan_sel_write(channel); + csr::rtio::o_timestamp_write(timestamp as u64); + csr::rtio::o_address_write(addr); + let data = slice::from_raw_parts(ptr, len); + for i in 0..data.len() { + write_volatile( + csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - i) as isize), + data[i]); + } csr::rtio::o_we_write(1); let status = csr::rtio::o_status_read(); if status != 0 { @@ -119,7 +156,7 @@ pub extern fn input_data(channel: u32) -> u32 { } } - let data = csr::rtio::i_data_read(); + let data = rtio_i_data_read(); csr::rtio::i_re_write(1); data } @@ -135,14 +172,14 @@ pub fn log(timestamp: i64, data: &[u8]) { word <<= 8; word |= data[i] as u32; if i % 4 == 0 { - csr::rtio::o_data_write(word); + rtio_o_data_write(word); csr::rtio::o_we_write(1); word = 0; } } word <<= 8; - csr::rtio::o_data_write(word); + rtio_o_data_write(word); csr::rtio::o_we_write(1); } } From 6799bb097ae52740c1dcd7e31ae4c0eabf38b6b9 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 22 Nov 2016 11:57:34 +0100 Subject: [PATCH 111/157] sawg: adapt to int32/int64 change --- artiq/coredevice/sawg.py | 7 ++++--- artiq/test/gateware/test_sawg_fe.py | 19 ++++++------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index d90eba9ed..6823bcf6d 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -1,3 +1,4 @@ +from numpy import int32, int64 from artiq.language.core import kernel, now_mu, portable from artiq.coredevice.rtio import rtio_output, rtio_output_list from artiq.language.types import TInt32, TInt64, TFloat, TList @@ -25,8 +26,8 @@ class Spline: @portable(flags=["fast-math"]) def to_mu64(self, value: TFloat) -> TList(TInt32): - v = int(round(value*self.scale), width=64) - return [int(v, width=32), int(v >> 32, width=32)] + v = int64(round(value*self.scale)) + return [int32(v), int32(v >> 32)] @kernel def set_mu(self, value: TInt32): @@ -68,7 +69,7 @@ class Spline: j = 0 for i, vi in enumerate(value): w = self.width + i*self.time_width - vi = int(round(vi*(self.scale*self.time_scale**i)), width=64) + vi = int64(round(vi*(self.scale*self.time_scale**i))) for k in range(0, w, 16): wi = (vi >> k) & 0xffff v[j//2] += wi << (16 * ((j + 1)//2 - j//2)) diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py index 325709340..bb1d03478 100644 --- a/artiq/test/gateware/test_sawg_fe.py +++ b/artiq/test/gateware/test_sawg_fe.py @@ -1,5 +1,6 @@ import unittest import numpy as np +from numpy import int32, int64 import migen as mg @@ -19,18 +20,10 @@ class RTIOManager: def rtio_output_list(self, *args, **kwargs): self.rtio_output(*args, **kwargs) - def int(self, value, width=32): - if width == 32: - return np.int32(value) - elif width == 64: - return np.int64(value) - else: - raise ValueError(width) - def patch(self, mod): assert not getattr(mod, "_saved", None) mod._saved = {} - for name in "rtio_output rtio_output_list int".split(): + for name in "rtio_output rtio_output_list".split(): mod._saved[name] = getattr(mod, name, None) setattr(mod, name, getattr(self, name)) @@ -47,7 +40,7 @@ class SAWGTest(unittest.TestCase): self.core = sim_devices.Core({}) self.core.coarse_ref_period = 8 self.channel = mg.ClockDomainsRenamer({"rio_phy": "sys"})( - Channel(width=16, parallelism=4)) + Channel(width=16, parallelism=2)) self.driver = sawg.SAWG({"core": self.core}, channel_base=0, parallelism=self.channel.parallelism) @@ -68,9 +61,9 @@ class SAWGTest(unittest.TestCase): self.rtio_manager.outputs, [ (0, 1, 0, int(round( (1 << self.driver.offset.width - 1)*.9))), - (2*8, 8, 0, [0, int(round( - (1 << self.driver.frequency0.width - 1) * - self.channel.parallelism*.1))]), + (2*8, 8, 0, [int(round( + (1 << self.driver.frequency0.width) / + self.channel.parallelism*.1)), 0]), (4*8, 1, 0, 0), ]) From fec34d605e1db98968eaed019b4341fac1f5e95a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 23 Nov 2016 14:56:20 +0100 Subject: [PATCH 112/157] runtime.rs/rtio.rs: style --- artiq/runtime.rs/libksupport/rtio.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/artiq/runtime.rs/libksupport/rtio.rs b/artiq/runtime.rs/libksupport/rtio.rs index 139e51f11..9783e52f4 100644 --- a/artiq/runtime.rs/libksupport/rtio.rs +++ b/artiq/runtime.rs/libksupport/rtio.rs @@ -35,11 +35,9 @@ pub unsafe fn rtio_o_data_write(w: u32) { #[inline(always)] pub unsafe fn rtio_i_data_read() -> u32 { read_volatile( - csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1) as isize) - ) + csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1) as isize)) } - #[inline(never)] unsafe fn process_exceptional_status(timestamp: i64, channel: u32, status: u32) { if status & RTIO_O_STATUS_FULL != 0 { From 617650f3b22f7b56fcd246d3a4fa6722d7ffe8db Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 24 Nov 2016 15:15:14 +0100 Subject: [PATCH 113/157] phaser: extract target --- README_PHASER.rst | 2 +- artiq/gateware/targets/kc705.py | 242 +--------------------------- artiq/gateware/targets/phaser.py | 265 +++++++++++++++++++++++++++++++ 3 files changed, 269 insertions(+), 240 deletions(-) create mode 100755 artiq/gateware/targets/phaser.py diff --git a/README_PHASER.rst b/README_PHASER.rst index 723d22601..5d4a3c7e4 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -74,7 +74,7 @@ Setup * Compile the ARTIQ Phaser bitstream, bios, and runtime (c.f. ARTIQ manual): :: - python -m artiq.gateware.targets.kc705 -H phaser --toolchain vivado + python -m artiq.gateware.targets.phaser --toolchain vivado * Run the following OpenOCD command to flash the ARTIQ phaser design: :: diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index fd11dc447..d4ac2a4f2 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -8,28 +8,16 @@ 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 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.interconnect import wishbone from misoc.cores import gpio -from misoc.cores import spi as spi_csr -from misoc.integration.soc_core import mem_decoder 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, nist_clock, nist_qc2, phaser +from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, - dds, spi, sawg) + dds, spi) from artiq import __version__ as artiq_version @@ -322,228 +310,6 @@ class NIST_QC2(_NIST_Ions): self.add_rtio(rtio_channels) -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(_ams101_dac) - platform.add_extension(phaser.fmc_adapter_io) - - 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 / KC705 " @@ -552,7 +318,7 @@ def main(): soc_kc705_args(parser) parser.add_argument("-H", "--hw-adapter", default="nist_clock", help="hardware adapter type: " - "nist_clock/nist_qc2/phaser " + "nist_clock/nist_qc2 " "(default: %(default)s)") args = parser.parse_args() @@ -561,8 +327,6 @@ def main(): cls = NIST_CLOCK elif hw_adapter == "nist_qc2": cls = NIST_QC2 - elif hw_adapter == "phaser": - cls = Phaser else: raise SystemExit("Invalid hardware adapter string (-H/--hw-adapter)") diff --git a/artiq/gateware/targets/phaser.py b/artiq/gateware/targets/phaser.py new file mode 100755 index 000000000..77a3aaf22 --- /dev/null +++ b/artiq/gateware/targets/phaser.py @@ -0,0 +1,265 @@ +#!/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, phaser +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(phaser.fmc_adapter_io) + + 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() From 80606529133e5d66512acad213080b6b0ca5b9f1 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 24 Nov 2016 15:21:03 +0100 Subject: [PATCH 114/157] phaser: use Inout_8X --- artiq/gateware/targets/phaser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/phaser.py b/artiq/gateware/targets/phaser.py index 77a3aaf22..918882e00 100755 --- a/artiq/gateware/targets/phaser.py +++ b/artiq/gateware/targets/phaser.py @@ -201,12 +201,12 @@ class Phaser(MiniSoC, AMPSoC): 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.Inout_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) + phy = ttl_serdes_7series.Inout_8X(self.ad9154.jesd.jsync) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32, ofifo_depth=2)) From 6fa2a6ebd87529a27e55d0bfa22a0f9e7fddcbe9 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 24 Nov 2016 15:53:14 +0100 Subject: [PATCH 115/157] phaser: move ad9154 spi/jesd api to rust --- artiq/runtime.rs/libksupport/ad9154.rs | 75 +++++++++++++++++++++++++ artiq/runtime.rs/libksupport/api.rs | 31 ++++++----- artiq/runtime.rs/libksupport/lib.rs | 2 + artiq/runtime/Makefile | 2 +- artiq/runtime/ad9154.c | 77 -------------------------- artiq/runtime/ad9154.h | 19 ------- 6 files changed, 96 insertions(+), 110 deletions(-) create mode 100644 artiq/runtime.rs/libksupport/ad9154.rs delete mode 100644 artiq/runtime/ad9154.c delete mode 100644 artiq/runtime/ad9154.h diff --git a/artiq/runtime.rs/libksupport/ad9154.rs b/artiq/runtime.rs/libksupport/ad9154.rs new file mode 100644 index 000000000..ab7026258 --- /dev/null +++ b/artiq/runtime.rs/libksupport/ad9154.rs @@ -0,0 +1,75 @@ +use board::csr; + +pub extern fn init() { + unsafe { + csr::ad9154::spi_offline_write(1); + csr::ad9154::spi_cs_polarity_write(0); + csr::ad9154::spi_clk_polarity_write(0); + csr::ad9154::spi_clk_phase_write(0); + csr::ad9154::spi_lsb_first_write(0); + csr::ad9154::spi_half_duplex_write(0); + csr::ad9154::spi_clk_div_write_write(16); + csr::ad9154::spi_clk_div_read_write(16); + csr::ad9154::spi_xfer_len_write_write(24); + csr::ad9154::spi_xfer_len_read_write(0); + csr::ad9154::spi_cs_write(csr::CONFIG_AD9154_DAC_CS); + csr::ad9154::spi_offline_write(0); + } +} + +const AD9_READ: u16 = 1 << 15; + +pub extern fn dac_write(addr: u16, data: u8) { + unsafe { + csr::ad9154::spi_data_write_write( + ((addr as u32) << 16) | ((data as u32) << 8)); + while csr::ad9154::spi_pending_read() != 0 {} + while csr::ad9154::spi_active_read() != 0 {} + } +} + +pub extern fn dac_read(addr: u16) -> u8 { + unsafe { + dac_write(AD9_READ | addr, 0); + csr::ad9154::spi_data_read_read() as u8 + } +} + +pub extern fn clk_write(addr: u16, data: u8) { + unsafe { + csr::ad9154::spi_cs_write(csr::CONFIG_AD9154_CLK_CS); + dac_write(addr, data); + csr::ad9154::spi_cs_write(csr::CONFIG_AD9154_DAC_CS); + } +} + +pub extern fn clk_read(addr: u16) -> u8 { + unsafe { + clk_write(AD9_READ | addr, 0); + csr::ad9154::spi_data_read_read() as u8 + } +} + +pub extern fn jesd_enable(en: u32) { + unsafe { + csr::ad9154::jesd_control_enable_write(en); + } +} + +pub extern fn jesd_ready() { + unsafe { + csr::ad9154::jesd_control_ready_read(); + } +} + +pub extern fn jesd_prbs(p: u32) { + unsafe { + csr::ad9154::jesd_control_prbs_config_write(p); + } +} + +pub extern fn jesd_stpl(en: u32) { + unsafe { + csr::ad9154::jesd_control_stpl_enable_write(en); + } +} diff --git a/artiq/runtime.rs/libksupport/api.rs b/artiq/runtime.rs/libksupport/api.rs index f7dbf41c0..d27e8964f 100644 --- a/artiq/runtime.rs/libksupport/api.rs +++ b/artiq/runtime.rs/libksupport/api.rs @@ -117,17 +117,22 @@ static mut API: &'static [(&'static str, *const ())] = &[ #[cfg(has_i2c)] api!(i2c_read = ::i2c::read), -// #if (defined CONFIG_AD9154_CS) - api!(ad9154_init), - api!(ad9154_write), - api!(ad9154_read), - - api!(ad9516_write), - api!(ad9516_read), - - api!(ad9154_jesd_enable), - api!(ad9154_jesd_ready), - api!(ad9154_jesd_prbs), - api!(ad9154_jesd_stpl), -// #endif + #[cfg(has_ad9154)] + api!(ad9154_init = ::ad9154::init), + #[cfg(has_ad9154)] + api!(ad9154_write = ::ad9154::dac_write), + #[cfg(has_ad9154)] + api!(ad9154_read = ::ad9154::dac_read), + #[cfg(has_ad9154)] + api!(ad9516_write = ::ad9154::clk_write), + #[cfg(has_ad9154)] + api!(ad9516_read = ::ad9154::clk_read), + #[cfg(has_ad9154)] + api!(ad9154_jesd_enable = ::ad9154::jesd_enable), + #[cfg(has_ad9154)] + api!(ad9154_jesd_ready = ::ad9154::jesd_ready), + #[cfg(has_ad9154)] + api!(ad9154_jesd_prbs = ::ad9154::jesd_prbs), + #[cfg(has_ad9154)] + api!(ad9154_jesd_stpl = ::ad9154::jesd_stpl), ]; diff --git a/artiq/runtime.rs/libksupport/lib.rs b/artiq/runtime.rs/libksupport/lib.rs index 08673e759..66aecbe98 100644 --- a/artiq/runtime.rs/libksupport/lib.rs +++ b/artiq/runtime.rs/libksupport/lib.rs @@ -52,6 +52,8 @@ macro_rules! artiq_raise { mod rtio; #[cfg(has_i2c)] mod i2c; +#[cfg(has_ad9154)] +mod ad9154; use core::{mem, ptr, slice, str}; use std::io::Cursor; diff --git a/artiq/runtime/Makefile b/artiq/runtime/Makefile index 853154c8a..a8387466b 100644 --- a/artiq/runtime/Makefile +++ b/artiq/runtime/Makefile @@ -4,7 +4,7 @@ include $(MISOC_DIRECTORY)/software/common.mak PYTHON ?= python3.5 OBJECTS := flash_storage.o main.o -OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o ad9154.o +OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug CORE_IO_COMMIT := d40c593f42fafbac1ff3d827f6df96338b5b7d8b diff --git a/artiq/runtime/ad9154.c b/artiq/runtime/ad9154.c deleted file mode 100644 index 5bc5e49e2..000000000 --- a/artiq/runtime/ad9154.c +++ /dev/null @@ -1,77 +0,0 @@ -#include - -#include -#include - -#include "artiq_personality.h" -#include "ad9154.h" - -#ifdef CONFIG_AD9154_DAC_CS - -void ad9154_init(void) -{ - ad9154_spi_offline_write(1); - ad9154_spi_cs_polarity_write(0); - ad9154_spi_clk_polarity_write(0); - ad9154_spi_clk_phase_write(0); - ad9154_spi_lsb_first_write(0); - ad9154_spi_half_duplex_write(0); - ad9154_spi_clk_div_write_write(16); - ad9154_spi_clk_div_read_write(16); - ad9154_spi_xfer_len_write_write(24); - ad9154_spi_xfer_len_read_write(0); - ad9154_spi_cs_write(CONFIG_AD9154_DAC_CS); - ad9154_spi_offline_write(0); -} - -#define AD9_READ (1 << 15) -#define AD9_XFER(w) ((w) << 13) - -void ad9154_write(uint16_t addr, uint8_t data) -{ - ad9154_spi_data_write_write( - ((AD9_XFER(0) | addr) << 16) | (data << 8)); - while (ad9154_spi_pending_read()); - while (ad9154_spi_active_read()); -} - -uint8_t ad9154_read(uint16_t addr) -{ - ad9154_write(AD9_READ | addr, 0); - return ad9154_spi_data_read_read(); -} - -void ad9516_write(uint16_t addr, uint8_t data) -{ - ad9154_spi_cs_write(CONFIG_AD9154_CLK_CS); - ad9154_write(addr, data); - ad9154_spi_cs_write(CONFIG_AD9154_DAC_CS); -} - -uint8_t ad9516_read(uint16_t addr) -{ - ad9516_write(AD9_READ | addr, 0); - return ad9154_spi_data_read_read(); -} - -void ad9154_jesd_enable(int en) -{ - ad9154_jesd_control_enable_write(en); -} - -int ad9154_jesd_ready(void) -{ - return ad9154_jesd_control_ready_read(); -} - -void ad9154_jesd_prbs(int p) -{ - ad9154_jesd_control_prbs_config_write(p); -} - -void ad9154_jesd_stpl(int en) -{ - ad9154_jesd_control_stpl_enable_write(en); -} - -#endif /* CONFIG_AD9154_DAC_CS */ diff --git a/artiq/runtime/ad9154.h b/artiq/runtime/ad9154.h deleted file mode 100644 index d6fa93d85..000000000 --- a/artiq/runtime/ad9154.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __AD9154_H -#define __AD9154_H - -#ifdef CONFIG_AD9154_DAC_CS - -void ad9154_init(void); -void ad9154_write(uint16_t addr, uint8_t data); -uint8_t ad9154_read(uint16_t addr); - -void ad9516_write(uint16_t addr, uint8_t data); -uint8_t ad9516_read(uint16_t addr); - -void ad9154_jesd_enable(int en); -int ad9154_jesd_ready(void); -void ad9154_jesd_prbs(int p); -void ad9154_jesd_stpl(int en); - -#endif -#endif From 55e37b41ecb0bc1d85363bf318e6e0b8a499b7e1 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 24 Nov 2016 15:55:26 +0100 Subject: [PATCH 116/157] phaser: use ttl_simple.Input for sync --- artiq/gateware/targets/phaser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/phaser.py b/artiq/gateware/targets/phaser.py index 918882e00..9d37d2419 100755 --- a/artiq/gateware/targets/phaser.py +++ b/artiq/gateware/targets/phaser.py @@ -206,7 +206,7 @@ class Phaser(MiniSoC, AMPSoC): rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32, ofifo_depth=2)) - phy = ttl_serdes_7series.Inout_8X(self.ad9154.jesd.jsync) + 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)) From 41779367b58af491f47d9660d78b822a3d83029f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 24 Nov 2016 16:04:13 +0100 Subject: [PATCH 117/157] phaser: adapt conda recipe --- conda/artiq-kc705-phaser/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-kc705-phaser/build.sh b/conda/artiq-kc705-phaser/build.sh index 78af5b75c..64625afc2 100644 --- a/conda/artiq-kc705-phaser/build.sh +++ b/conda/artiq-kc705-phaser/build.sh @@ -6,7 +6,7 @@ BUILD_SETTINGS_FILE=$HOME/.m-labs/build_settings.sh SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kc705-phaser mkdir -p $SOC_PREFIX -$PYTHON -m artiq.gateware.targets.kc705 -H phaser --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE +$PYTHON -m artiq.gateware.targets.phaser --toolchain vivado $MISOC_EXTRA_VIVADO_CMDLINE cp misoc_phaser_kc705/gateware/top.bit $SOC_PREFIX cp misoc_phaser_kc705/software/bios/bios.bin $SOC_PREFIX cp misoc_phaser_kc705/software/runtime/runtime.fbi $SOC_PREFIX From 23fd2259474cc171e3ecf26f9f8d1701d027b7cc Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 14:49:07 +0100 Subject: [PATCH 118/157] sawg: spline knot packing/conversion, unittest --- artiq/coredevice/sawg.py | 115 +++++++++++++++++++++------- artiq/test/gateware/test_sawg_fe.py | 63 ++++++++++++--- 2 files changed, 139 insertions(+), 39 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 6823bcf6d..da4c9a5be 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -1,5 +1,5 @@ from numpy import int32, int64 -from artiq.language.core import kernel, now_mu, portable +from artiq.language.core import kernel, now_mu, portable, delay from artiq.coredevice.rtio import rtio_output, rtio_output_list from artiq.language.types import TInt32, TInt64, TFloat, TList @@ -12,22 +12,22 @@ class Spline: self.core = core_device self.channel = channel self.width = width - self.scale = (1 << width) / scale + self.scale = (1 << width) * scale self.time_width = time_width - self.time_scale = (1 << time_width) / core_device.coarse_ref_period + self.time_scale = (1 << time_width) * core_device.coarse_ref_period - @portable(flags=["fast-math"]) + @portable(flags={"fast-math"}) def to_mu(self, value: TFloat) -> TInt32: return int(round(value*self.scale)) - @portable(flags=["fast-math"]) + @portable(flags={"fast-math"}) def from_mu(self, value: TInt32) -> TFloat: return value/self.scale - @portable(flags=["fast-math"]) + @portable(flags={"fast-math"}) def to_mu64(self, value: TFloat) -> TList(TInt32): v = int64(round(value*self.scale)) - return [int32(v), int32(v >> 32)] + return [int32(v), int32((v >> 32) & 0xffffffff)] @kernel def set_mu(self, value: TInt32): @@ -61,20 +61,45 @@ class Spline: """ rtio_output_list(now_mu(), self.channel, 0, value) - @portable(flags=["fast-math"]) - def coeff_to_mu(self, value: TList(TFloat)) -> TList(TInt32): - l = len(value) - w = l*self.width + (l - 1)*l//2*self.time_width - v = [0] * ((w + 31)//32) - j = 0 - for i, vi in enumerate(value): - w = self.width + i*self.time_width - vi = int64(round(vi*(self.scale*self.time_scale**i))) - for k in range(0, w, 16): - wi = (vi >> k) & 0xffff - v[j//2] += wi << (16 * ((j + 1)//2 - j//2)) - j += 1 - return v + @portable(flags={"fast-math"}) + def pack_coeff_mu(self, coeff: TList(TInt64)) -> TList(TInt32): + n = len(coeff) + width = n*self.width + (n - 1)*n//2*self.time_width + packed = [int32(0)] * ((width + 31)//32) + pos = 0 + for i in range(n): + wi = self.width + i*self.time_width + ci = coeff[i] + while wi: + j = pos//32 + used = pos - 32*j + avail = 32 - used + if avail > wi: + avail = wi + packed[j] |= (ci & ((1 << avail) - 1)) << used + ci >>= avail + wi -= avail + pos += avail + return packed + + @portable(flags={"fast-math"}) + def coeff_to_mu(self, coeff: TList(TFloat)) -> TList(TInt32): + n = len(coeff) + coeff64 = [int64(0)] * n + for i in range(n): + vi = coeff[i] * self.scale + for j in range(i): + vi *= self.time_scale + vi = int(round(vi)) + coeff64[i] = vi + # artiq.wavesynth.coefficients.discrete_compensate: + continue + if i == 2: + coeff64[1] += vi >> (self.time_width + 1) + elif i == 3: + coeff64[2] += vi >> self.time_width + coeff64[1] += (vi // 3) >> (2*self.time_width + 1) + return self.pack_coeff_mu(coeff64) @kernel def set_list(self, value: TList(TFloat)): @@ -85,6 +110,42 @@ class Spline: """ self.set_list_mu(self.coeff_to_mu(value)) + @kernel(flags={"fast-math"}) + def smooth(self, start, stop, duration, order): + """Initiate an interpolated value change. + + The third order interpolation is constrained to have zero first + order derivative at both start and stop. + + For zeroth order (step) interpolation, the step is at duration/2. + + For first order and third order interpolation (linear and cubic) + the interpolator needs to be stopped (or fed a new spline knot) + explicitly at the stop time. + + This method advances the timeline by `duration`. + + :param start: Initial value of the change. + :param stop: Final value of the change. + :param duration: Duration of the interpolation. + :param order: Order of the interpolation. Only 0, 1, + and 3 are valid: step, linear, cubic. + """ + if order == 0: + delay(duration/2) + self.set_list([stop]) + delay(duration/2) + elif order == 1: + self.set_list([start, (stop - start)/duration]) + delay(duration) + elif order == 3: + v2 = 6*(stop - start)/(duration*duration) + self.set_list([start, 0., v2, -2*v2/duration]) + delay(duration) + else: + raise ValueError("Invalid interpolation order. " + "Supported orders are: 0, 1, 3.") + class SAWG: """Smart arbitrary waveform generator channel. @@ -119,21 +180,21 @@ class SAWG: cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain # cfg: channel_base self.offset = Spline(width, time_width, channel_base + 1, - self.core, 2) + self.core, 1/2) self.amplitude1 = Spline(width, time_width, channel_base + 2, - self.core, 2*cordic_gain**2) + self.core, 1/(2*cordic_gain**2)) self.frequency1 = Spline(3*width, time_width, channel_base + 3, - self.core, self.core.coarse_ref_period) + self.core, 1/self.core.coarse_ref_period) self.phase1 = Spline(width, time_width, channel_base + 4, self.core, 1.) self.amplitude2 = Spline(width, time_width, channel_base + 5, - self.core, 2*cordic_gain**2) + self.core, 1/(2*cordic_gain**2)) self.frequency2 = Spline(3*width, time_width, channel_base + 6, - self.core, self.core.coarse_ref_period) + self.core, 1/self.core.coarse_ref_period) self.phase2 = Spline(width, time_width, channel_base + 7, self.core, 1.) self.frequency0 = Spline(2*width, time_width, channel_base + 8, self.core, - parallelism/self.core.coarse_ref_period) + self.core.coarse_ref_period/parallelism) self.phase0 = Spline(width, time_width, channel_base + 9, self.core, 1.) diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py index bb1d03478..a93f95daa 100644 --- a/artiq/test/gateware/test_sawg_fe.py +++ b/artiq/test/gateware/test_sawg_fe.py @@ -1,5 +1,4 @@ import unittest -import numpy as np from numpy import int32, int64 import migen as mg @@ -21,7 +20,7 @@ class RTIOManager: self.rtio_output(*args, **kwargs) def patch(self, mod): - assert not getattr(mod, "_saved", None) + assert not hasattr(mod, "_saved") mod._saved = {} for name in "rtio_output rtio_output_list".split(): mod._saved[name] = getattr(mod, name, None) @@ -63,7 +62,8 @@ class SAWGTest(unittest.TestCase): (1 << self.driver.offset.width - 1)*.9))), (2*8, 8, 0, [int(round( (1 << self.driver.frequency0.width) / - self.channel.parallelism*.1)), 0]), + self.channel.parallelism*d.core.coarse_ref_period*.1)), + 0]), (4*8, 1, 0, 0), ]) @@ -79,7 +79,7 @@ class SAWGTest(unittest.TestCase): yield phy.rtlink.o.stb.eq(0) rt = dut.phys[channel].rtlink.o if isinstance(data, list): - data = sum(d << i*32 for i, d in enumerate(data)) + data = sum(int(d) << (i*32) for i, d in enumerate(data)) yield rt.data.eq(int(data)) yield rt.stb.eq(1) assert not (yield rt.busy) @@ -98,10 +98,9 @@ class SAWGTest(unittest.TestCase): vcd_name="dds.vcd") return sum(data, []) - def test_channel(self): + def test_run_channel(self): self.test_make_events() out = self.run_channel(self.rtio_manager.outputs) - print(out) def test_coeff(self): import struct @@ -111,10 +110,11 @@ class SAWGTest(unittest.TestCase): p = ch.coeff_to_mu(v) t = ch.time_width w = ch.width - p0 = [struct.pack("<" + "_hiqq"[(w + i*t)//16], - int(round(vi*ch.scale*ch.time_scale**i)) - )[:(w + i*t)//8] + p0 = [int(round(vi*ch.scale*ch.time_scale**i)) for i, vi in enumerate(v)] + p0 = [struct.pack("<" + "_bhiiqqqq"[(w + i*t)//8], vi + )[:(w + i*t)//8] + for i, vi in enumerate(p0)] p0 = b"".join(p0) if len(p0) % 4: p0 += b"\x00"*(4 - len(p0) % 4) @@ -129,6 +129,45 @@ class SAWGTest(unittest.TestCase): d.offset.set_list([0]) delay_mu(1*8) out = self.run_channel(self.rtio_manager.outputs) - self.assertEqual( - out, sum(([100 + i*10]*self.channel.parallelism - for i in range(11)), [])) + for i in range(len(out)//2): + with self.subTest(i): + v = 100 + i*10 + self.assertEqual(out[2*i], v) + self.assertEqual(out[2*i+1], v) + + def test_pack(self): + ch = self.driver.offset + self.assertEqual(ch.pack_coeff_mu([1]), [1]) + self.assertEqual(ch.pack_coeff_mu([1, 1 << 16]), [1, 1]) + self.assertEqual(ch.pack_coeff_mu([1, 1 << 32]), [1, 0]) + self.assertEqual(ch.pack_coeff_mu([0x1234, 0xa5a5a5a5]), + [0xa5a51234, 0xa5a5]) + self.assertEqual(ch.pack_coeff_mu([1, 2, 3, 4]), + [0x20001, 0x30000, 0, 4, 0]) + self.assertEqual(ch.pack_coeff_mu([-1, -2, -3, -4]), + [0xfffeffff, 0xfffdffff, 0xffffffff, + 0xfffffffc, 0xffffffff]) + self.assertEqual(ch.pack_coeff_mu([0, -1, 0, -1]), + [0xffff0000, 0x0000ffff, 0, + 0xffffffff, 0xffffffff]) + + def test_smooth_linear(self): + ch = self.driver.offset + ch.smooth(.1, .2, 13*ch.core.coarse_ref_period, 1) + ch.set(.2) + delay_mu(1*8) + out = self.run_channel(self.rtio_manager.outputs) + a = int(round(.1*ch.scale)) + da = a//13 + for i in range(len(out)//2): + with self.subTest(i): + v = a + i*da + self.assertEqual(out[2*i], v) + self.assertEqual(out[2*i+1], v) + + def test_smooth_cubic(self): + ch = self.driver.offset + ch.smooth(.1, .2, 13*ch.core.coarse_ref_period, 3) + ch.set(.2) + delay_mu(1*8) + out = self.run_channel(self.rtio_manager.outputs) From 7657cf12643c0b67bfb574c3e9cba24cc1d3c0b1 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 14:55:15 +0100 Subject: [PATCH 119/157] phaser: bump misoc/migen --- conda/artiq-kc705-phaser/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-kc705-phaser/meta.yaml b/conda/artiq-kc705-phaser/meta.yaml index 3d8d0f5ed..bb6c61096 100644 --- a/conda/artiq-kc705-phaser/meta.yaml +++ b/conda/artiq-kc705-phaser/meta.yaml @@ -12,8 +12,8 @@ build: requirements: build: - - migen 0.4 - - misoc 0.4 + - migen 0.5.dev + - misoc 0.5.dev - jesd204b 0.2 - llvm-or1k - binutils-or1k-linux >=2.27 From 7816078d6b18c74008c33a9fc21ac65e8969c2fa Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 15:11:18 +0100 Subject: [PATCH 120/157] phaser/demo: update --- artiq/examples/phaser/repository/demo.py | 38 ++++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/artiq/examples/phaser/repository/demo.py b/artiq/examples/phaser/repository/demo.py index ba67b96a4..221016904 100644 --- a/artiq/examples/phaser/repository/demo.py +++ b/artiq/examples/phaser/repository/demo.py @@ -18,33 +18,33 @@ class SAWGTest(EnvExperiment): self.ttl_sma.output() while True: - self.sawg0.set_amplitude(0.) - self.sawg0.set_frequency(0*MHz) - self.sawg1.set_amplitude(0.) - self.sawg1.set_frequency(0*MHz) + self.sawg0.amplitude1.set(0.) + self.sawg0.frequency0.set(0*MHz) + self.sawg1.amplitude1.set(0.) + self.sawg1.frequency0.set(0*MHz) delay(20*ms) - self.sawg0.set_amplitude(.4) - self.sawg0.set_frequency(10*MHz) - self.sawg0.set_phase(0.) - self.sawg1.set_amplitude(.4) - self.sawg1.set_frequency(10*MHz) - self.sawg1.set_phase(0.) + self.sawg0.amplitude1.set(.4) + self.sawg0.frequency0.set(10*MHz) + self.sawg0.phase0.set(0.) + self.sawg1.amplitude1.set(.4) + self.sawg1.frequency0.set(10*MHz) + self.sawg1.phase0.set(0.) self.ttl_sma.pulse(200*ns) - self.sawg1.set_amplitude(.1) + self.sawg1.amplitude1.set(.1) delay(200*ns) - self.sawg1.set_amplitude(-.4) + self.sawg1.amplitude1.set(-.4) self.ttl_sma.pulse(200*ns) - self.sawg1.set_amplitude(.4) + self.sawg1.amplitude1.set(.4) delay(200*ns) - self.sawg1.set_phase(.25) + self.sawg1.phase0.set(.25) self.ttl_sma.pulse(200*ns) - self.sawg1.set_phase(.5) + self.sawg1.phase0.set(.5) delay(200*ns) - self.sawg0.set_phase(.5) + self.sawg0.phase0.set(.5) self.ttl_sma.pulse(200*ns) - self.sawg1.set_frequency(30*MHz) + self.sawg1.frequency0.set(30*MHz) delay(200*ns) - self.sawg1.set_frequency(10*MHz) - self.sawg1.set_phase(0.) + self.sawg1.frequency0.set(10*MHz) + self.sawg1.phase0.set(0.) self.ttl_sma.pulse(200*ns) From 27160f5912609dad9bee52d5fd79e913ba63ba3a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 15:28:10 +0100 Subject: [PATCH 121/157] phaser: make sysref input only for timing --- artiq/gateware/targets/phaser.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/phaser.py b/artiq/gateware/targets/phaser.py index 9d37d2419..6208ef5c6 100755 --- a/artiq/gateware/targets/phaser.py +++ b/artiq/gateware/targets/phaser.py @@ -22,7 +22,8 @@ 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, phaser +from artiq.gateware import rtio +from artiq.gateware.phaser import fmc_adapter_io from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, sawg) from artiq import __version__ as artiq_version @@ -172,7 +173,7 @@ class Phaser(MiniSoC, AMPSoC): ]) platform = self.platform - platform.add_extension(phaser.fmc_adapter_io) + platform.add_extension(fmc_adapter_io) self.submodules.leds = gpio.GPIOOut(Cat( platform.request("user_led", 0), @@ -201,7 +202,7 @@ class Phaser(MiniSoC, AMPSoC): rtio_channels.append(rtio.Channel.from_phy(phy)) sysref_pads = platform.request("ad9154_sysref") - phy = ttl_serdes_7series.Inout_8X(sysref_pads.p, sysref_pads.n) + 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)) From 82c651c17aca20d37bcf45d65da55e2813b77847 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 15:40:23 +0100 Subject: [PATCH 122/157] phaser: remove trivial sawg demo --- artiq/examples/phaser/repository/sawg.py | 33 ------------------------ 1 file changed, 33 deletions(-) delete mode 100644 artiq/examples/phaser/repository/sawg.py diff --git a/artiq/examples/phaser/repository/sawg.py b/artiq/examples/phaser/repository/sawg.py deleted file mode 100644 index 8710a34d2..000000000 --- a/artiq/examples/phaser/repository/sawg.py +++ /dev/null @@ -1,33 +0,0 @@ -from artiq.experiment import * - - -class SAWGTest(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("led") - - self.setattr_device("sawg0") - self.setattr_device("sawg1") - self.setattr_device("sawg2") - self.setattr_device("sawg3") - - @kernel - def run(self): - self.core.break_realtime() - - self.sawg0.amplitude1.set(.1) - self.sawg0.frequency0.set(10*MHz) - self.sawg0.phase0.set(0.) - self.sawg1.amplitude1.set(-.9) - self.sawg1.frequency0.set(20*MHz) - self.sawg1.phase0.set(0.) - self.sawg2.amplitude1.set(.5) - self.sawg2.frequency0.set(30*MHz) - self.sawg2.phase0.set(0.) - self.sawg3.amplitude1.set(.5) - self.sawg3.frequency0.set(30*MHz) - self.sawg3.phase0.set(.5) - - for i in range(10): - self.led.pulse(100*ms) - delay(100*ms) From a3d9e21b8c5eec9703a45bc60cdbb13f012fdc11 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 16:58:26 +0100 Subject: [PATCH 123/157] sawg: artiq-python changes --- artiq/coredevice/sawg.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index da4c9a5be..53b9c669f 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -90,15 +90,15 @@ class Spline: vi = coeff[i] * self.scale for j in range(i): vi *= self.time_scale - vi = int(round(vi)) - coeff64[i] = vi + ci = int(round(vi)) + coeff64[i] = ci # artiq.wavesynth.coefficients.discrete_compensate: continue if i == 2: - coeff64[1] += vi >> (self.time_width + 1) + coeff64[1] += ci >> (self.time_width + 1) elif i == 3: - coeff64[2] += vi >> self.time_width - coeff64[1] += (vi // 3) >> (2*self.time_width + 1) + coeff64[2] += ci >> self.time_width + coeff64[1] += (ci // 3) >> (2*self.time_width + 1) return self.pack_coeff_mu(coeff64) @kernel @@ -111,7 +111,8 @@ class Spline: self.set_list_mu(self.coeff_to_mu(value)) @kernel(flags={"fast-math"}) - def smooth(self, start, stop, duration, order): + def smooth(self, start: TFloat, stop: TFloat, duration: TFloat, + order: TInt32): """Initiate an interpolated value change. The third order interpolation is constrained to have zero first From c53040e1e43b96ded4e58b7a97b4c5e0d8dbd853 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 17:01:39 +0100 Subject: [PATCH 124/157] sawg: work around #632 --- artiq/coredevice/sawg.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 53b9c669f..f7897f212 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -54,7 +54,7 @@ class Spline: rtio_output_list(now_mu(), self.channel, 0, self.to_mu64(value)) @kernel - def set_list_mu(self, value: TList(TInt32)): + def set_list_mu(self, value): """Set spline raw values. :param value: Spline packed raw values. @@ -62,7 +62,7 @@ class Spline: rtio_output_list(now_mu(), self.channel, 0, value) @portable(flags={"fast-math"}) - def pack_coeff_mu(self, coeff: TList(TInt64)) -> TList(TInt32): + def pack_coeff_mu(self, coeff) -> TList(TInt32): n = len(coeff) width = n*self.width + (n - 1)*n//2*self.time_width packed = [int32(0)] * ((width + 31)//32) @@ -83,7 +83,7 @@ class Spline: return packed @portable(flags={"fast-math"}) - def coeff_to_mu(self, coeff: TList(TFloat)) -> TList(TInt32): + def coeff_to_mu(self, coeff) -> TList(TInt32): n = len(coeff) coeff64 = [int64(0)] * n for i in range(n): @@ -102,7 +102,7 @@ class Spline: return self.pack_coeff_mu(coeff64) @kernel - def set_list(self, value: TList(TFloat)): + def set_list(self, value): """Set spline coefficients. :param value: List of floating point spline knot coefficients, From 313aa32779dc46beab938209c925a462d86138e3 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 17:20:02 +0100 Subject: [PATCH 125/157] sawg: artiq-python list scoping --- artiq/coredevice/sawg.py | 28 ++++++++++---------- artiq/test/gateware/test_sawg_fe.py | 40 +++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index f7897f212..647e30516 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -62,44 +62,36 @@ class Spline: rtio_output_list(now_mu(), self.channel, 0, value) @portable(flags={"fast-math"}) - def pack_coeff_mu(self, coeff) -> TList(TInt32): - n = len(coeff) - width = n*self.width + (n - 1)*n//2*self.time_width - packed = [int32(0)] * ((width + 31)//32) + def pack_coeff_mu(self, coeff, packed): pos = 0 - for i in range(n): + for i in range(len(coeff)): wi = self.width + i*self.time_width ci = coeff[i] - while wi: + while wi != 0: j = pos//32 used = pos - 32*j avail = 32 - used if avail > wi: avail = wi - packed[j] |= (ci & ((1 << avail) - 1)) << used + packed[j] |= int32(ci & ((1 << avail) - 1)) << used ci >>= avail wi -= avail pos += avail - return packed @portable(flags={"fast-math"}) - def coeff_to_mu(self, coeff) -> TList(TInt32): - n = len(coeff) - coeff64 = [int64(0)] * n - for i in range(n): + def coeff_to_mu(self, coeff, coeff64): + for i in range(len(coeff)): vi = coeff[i] * self.scale for j in range(i): vi *= self.time_scale ci = int(round(vi)) coeff64[i] = ci # artiq.wavesynth.coefficients.discrete_compensate: - continue if i == 2: coeff64[1] += ci >> (self.time_width + 1) elif i == 3: coeff64[2] += ci >> self.time_width coeff64[1] += (ci // 3) >> (2*self.time_width + 1) - return self.pack_coeff_mu(coeff64) @kernel def set_list(self, value): @@ -108,7 +100,13 @@ class Spline: :param value: List of floating point spline knot coefficients, lowest order (constant) coefficient first. """ - self.set_list_mu(self.coeff_to_mu(value)) + n = len(value) + width = n*self.width + (n - 1)*n//2*self.time_width + coeff64 = [int64(0)] * n + packed = [int32(0)] * ((width + 31)//32) + self.coeff_to_mu(value, coeff64) + self.pack_coeff_mu(coeff64, packed) + self.set_list_mu(packed) @kernel(flags={"fast-math"}) def smooth(self, start: TFloat, stop: TFloat, duration: TFloat, diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py index a93f95daa..21230c97f 100644 --- a/artiq/test/gateware/test_sawg_fe.py +++ b/artiq/test/gateware/test_sawg_fe.py @@ -104,12 +104,18 @@ class SAWGTest(unittest.TestCase): def test_coeff(self): import struct - for v in [-.1], [.1, -.01], [.1, .01, -.00001], \ - [.1, .01, .00001, -.000000001]: + # these get discrete_compensate + # [.1, .01, -.00001], [.1, .01, .00001, -.000000001] + for v in [-.1], [.1, -.01]: ch = self.driver.offset - p = ch.coeff_to_mu(v) + q = [0] * len(v) + ch.coeff_to_mu(v, q) + n = len(v) t = ch.time_width w = ch.width + p = [0] * ((n*w + (n - 1)*n//2*t + 31)//32) + ch.pack_coeff_mu(q, p) + p = [_ & 0xffffffff for _ in p] p0 = [int(round(vi*ch.scale*ch.time_scale**i)) for i, vi in enumerate(v)] p0 = [struct.pack("<" + "_bhiiqqqq"[(w + i*t)//8], vi @@ -135,19 +141,28 @@ class SAWGTest(unittest.TestCase): self.assertEqual(out[2*i], v) self.assertEqual(out[2*i+1], v) - def test_pack(self): + def pack(self, v): + n = len(v) ch = self.driver.offset - self.assertEqual(ch.pack_coeff_mu([1]), [1]) - self.assertEqual(ch.pack_coeff_mu([1, 1 << 16]), [1, 1]) - self.assertEqual(ch.pack_coeff_mu([1, 1 << 32]), [1, 0]) - self.assertEqual(ch.pack_coeff_mu([0x1234, 0xa5a5a5a5]), + t = ch.time_width + w = ch.width + p = [0] * ((n*w + (n - 1)*n//2*t + 31)//32) + ch.pack_coeff_mu(v, p) + p = [_ & 0xffffffff for _ in p] + return p + + def test_pack(self): + self.assertEqual(self.pack([1]), [1]) + self.assertEqual(self.pack([1, 1 << 16]), [1, 1]) + self.assertEqual(self.pack([1, 1 << 32]), [1, 0]) + self.assertEqual(self.pack([0x1234, 0xa5a5a5a5]), [0xa5a51234, 0xa5a5]) - self.assertEqual(ch.pack_coeff_mu([1, 2, 3, 4]), + self.assertEqual(self.pack([1, 2, 3, 4]), [0x20001, 0x30000, 0, 4, 0]) - self.assertEqual(ch.pack_coeff_mu([-1, -2, -3, -4]), + self.assertEqual(self.pack([-1, -2, -3, -4]), [0xfffeffff, 0xfffdffff, 0xffffffff, 0xfffffffc, 0xffffffff]) - self.assertEqual(ch.pack_coeff_mu([0, -1, 0, -1]), + self.assertEqual(self.pack([0, -1, 0, -1]), [0xffff0000, 0x0000ffff, 0, 0xffffffff, 0xffffffff]) @@ -171,3 +186,6 @@ class SAWGTest(unittest.TestCase): ch.set(.2) delay_mu(1*8) out = self.run_channel(self.rtio_manager.outputs) + # import matplotlib.pyplot as plt + # plt.plot(out) + # plt.show() From f6fc7f9216182bb6db27be16cdc9d1f006649a23 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 17:22:55 +0100 Subject: [PATCH 126/157] rtio: rtio_output_{list->wide} --- artiq/coredevice/rtio.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/rtio.py b/artiq/coredevice/rtio.py index 3dec674df..471a48c31 100644 --- a/artiq/coredevice/rtio.py +++ b/artiq/coredevice/rtio.py @@ -3,12 +3,13 @@ from artiq.language.types import TInt64, TInt32, TNone, TList @syscall(flags={"nowrite"}) -def rtio_output(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32) -> TNone: +def rtio_output(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32 + ) -> TNone: raise NotImplementedError("syscall not simulated") @syscall(flags={"nowrite"}) -def rtio_output_list(time_mu: TInt64, channel: TInt32, addr: TInt32, +def rtio_output_wide(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TList(TInt32)) -> TNone: raise NotImplementedError("syscall not simulated") From 4a03e3fce02a7261e053a37b9c6d02db3f311486 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 17:23:06 +0100 Subject: [PATCH 127/157] sawg: rtio_output_wide --- artiq/coredevice/sawg.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 647e30516..7afe218e4 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -1,6 +1,6 @@ from numpy import int32, int64 from artiq.language.core import kernel, now_mu, portable, delay -from artiq.coredevice.rtio import rtio_output, rtio_output_list +from artiq.coredevice.rtio import rtio_output, rtio_output_wide from artiq.language.types import TInt32, TInt64, TFloat, TList @@ -51,15 +51,15 @@ class Spline: :param value: Spline value relative to full-scale. """ - rtio_output_list(now_mu(), self.channel, 0, self.to_mu64(value)) + rtio_output_wide(now_mu(), self.channel, 0, self.to_mu64(value)) @kernel - def set_list_mu(self, value): + def set_coeff_mu(self, value): """Set spline raw values. :param value: Spline packed raw values. """ - rtio_output_list(now_mu(), self.channel, 0, value) + rtio_output_wide(now_mu(), self.channel, 0, value) @portable(flags={"fast-math"}) def pack_coeff_mu(self, coeff, packed): @@ -94,7 +94,7 @@ class Spline: coeff64[1] += (ci // 3) >> (2*self.time_width + 1) @kernel - def set_list(self, value): + def set_coeff(self, value): """Set spline coefficients. :param value: List of floating point spline knot coefficients, @@ -106,7 +106,7 @@ class Spline: packed = [int32(0)] * ((width + 31)//32) self.coeff_to_mu(value, coeff64) self.pack_coeff_mu(coeff64, packed) - self.set_list_mu(packed) + self.set_coeff_mu(packed) @kernel(flags={"fast-math"}) def smooth(self, start: TFloat, stop: TFloat, duration: TFloat, @@ -132,14 +132,14 @@ class Spline: """ if order == 0: delay(duration/2) - self.set_list([stop]) + self.set_coeff([stop]) delay(duration/2) elif order == 1: - self.set_list([start, (stop - start)/duration]) + self.set_coeff([start, (stop - start)/duration]) delay(duration) elif order == 3: v2 = 6*(stop - start)/(duration*duration) - self.set_list([start, 0., v2, -2*v2/duration]) + self.set_coeff([start, 0., v2, -2*v2/duration]) delay(duration) else: raise ValueError("Invalid interpolation order. " From d9dd79fb1af638b913b112361cf8b1e769e45528 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 17:33:43 +0100 Subject: [PATCH 128/157] sawg: int32 artiq python --- artiq/coredevice/sawg.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 7afe218e4..0a72bddc4 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -18,16 +18,15 @@ class Spline: @portable(flags={"fast-math"}) def to_mu(self, value: TFloat) -> TInt32: - return int(round(value*self.scale)) + return int32(round(value*self.scale)) @portable(flags={"fast-math"}) def from_mu(self, value: TInt32) -> TFloat: return value/self.scale @portable(flags={"fast-math"}) - def to_mu64(self, value: TFloat) -> TList(TInt32): - v = int64(round(value*self.scale)) - return [int32(v), int32((v >> 32) & 0xffffffff)] + def to_mu64(self, value: TFloat) -> TInt64: + return int64(round(value*self.scale)) @kernel def set_mu(self, value: TInt32): @@ -51,7 +50,9 @@ class Spline: :param value: Spline value relative to full-scale. """ - rtio_output_wide(now_mu(), self.channel, 0, self.to_mu64(value)) + v = self.to_mu64(value) + l = [int32(v), int32(v >> 32)] + rtio_output_wide(now_mu(), self.channel, 0, l) @kernel def set_coeff_mu(self, value): @@ -84,7 +85,7 @@ class Spline: vi = coeff[i] * self.scale for j in range(i): vi *= self.time_scale - ci = int(round(vi)) + ci = int64(round(vi)) coeff64[i] = ci # artiq.wavesynth.coefficients.discrete_compensate: if i == 2: From 4f813c49772490eb003632f210fc9809e8135251 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 18:11:38 +0100 Subject: [PATCH 129/157] test/sawg: rtio_output_wide fixes --- artiq/test/gateware/test_sawg_fe.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py index 21230c97f..f381dcfd4 100644 --- a/artiq/test/gateware/test_sawg_fe.py +++ b/artiq/test/gateware/test_sawg_fe.py @@ -16,13 +16,13 @@ class RTIOManager: def rtio_output(self, now, channel, addr, data): self.outputs.append((now, channel, addr, data)) - def rtio_output_list(self, *args, **kwargs): + def rtio_output_wide(self, *args, **kwargs): self.rtio_output(*args, **kwargs) def patch(self, mod): assert not hasattr(mod, "_saved") mod._saved = {} - for name in "rtio_output rtio_output_list".split(): + for name in "rtio_output rtio_output_wide".split(): mod._saved[name] = getattr(mod, name, None) setattr(mod, name, getattr(self, name)) @@ -130,9 +130,9 @@ class SAWGTest(unittest.TestCase): def test_linear(self): d = self.driver - d.offset.set_list_mu([100, 10]) + d.offset.set_coeff_mu([100, 10]) delay_mu(10*8) - d.offset.set_list([0]) + d.offset.set_coeff([0]) delay_mu(1*8) out = self.run_channel(self.rtio_manager.outputs) for i in range(len(out)//2): From d8b5eac856027ebd64824d99fd038aecb84ac450 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 20:51:29 +0100 Subject: [PATCH 130/157] sawg: style --- artiq/coredevice/sawg.py | 4 ++-- artiq/gateware/dsp/sawg.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 0a72bddc4..8bfe4edf9 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -89,10 +89,10 @@ class Spline: coeff64[i] = ci # artiq.wavesynth.coefficients.discrete_compensate: if i == 2: - coeff64[1] += ci >> (self.time_width + 1) + coeff64[1] += ci >> self.time_width + 1 elif i == 3: coeff64[2] += ci >> self.time_width - coeff64[1] += (ci // 3) >> (2*self.time_width + 1) + coeff64[1] += ci // 6 >> 2*self.time_width @kernel def set_coeff(self, value): diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 9ff89d72e..4f13f87c1 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -88,8 +88,7 @@ class SplineParallelDDS(SplineParallelDUC): a = Spline(order=orders.a, width=widths.a) self.a = a.tri(widths.t) self.submodules += a - super().__init__(widths._replace(a=len(self.a.a0)), - orders, **kwargs) + super().__init__(widths._replace(a=len(self.a.a0)), orders, **kwargs) ### From b736dd0df72ddcd93b81d232650e1e26389432e0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 20:52:02 +0100 Subject: [PATCH 131/157] sawg: test w/o discrete_compensate --- artiq/coredevice/sawg.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 8bfe4edf9..89b4d7fd2 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -88,6 +88,7 @@ class Spline: ci = int64(round(vi)) coeff64[i] = ci # artiq.wavesynth.coefficients.discrete_compensate: + continue if i == 2: coeff64[1] += ci >> self.time_width + 1 elif i == 3: From dbf72f5fde18cd3522ef37a013b477b2a204ba0a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 20:52:51 +0100 Subject: [PATCH 132/157] sawg: extend unittests --- artiq/test/gateware/test_sawg_fe.py | 87 +++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 23 deletions(-) diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py index f381dcfd4..8c90df3f6 100644 --- a/artiq/test/gateware/test_sawg_fe.py +++ b/artiq/test/gateware/test_sawg_fe.py @@ -1,10 +1,10 @@ import unittest -from numpy import int32, int64 import migen as mg from artiq.coredevice import sawg -from artiq.language import delay_mu, core as core_language +from artiq.language import (at_mu, now_mu, delay_mu, delay, + core as core_language) from artiq.gateware.rtio.phy.sawg import Channel from artiq.sim import devices as sim_devices, time as sim_time @@ -37,7 +37,7 @@ class SAWGTest(unittest.TestCase): self.rtio_manager = RTIOManager() self.rtio_manager.patch(sawg) self.core = sim_devices.Core({}) - self.core.coarse_ref_period = 8 + self.core.coarse_ref_period = 1 self.channel = mg.ClockDomainsRenamer({"rio_phy": "sys"})( Channel(width=16, parallelism=2)) self.driver = sawg.SAWG({"core": self.core}, channel_base=0, @@ -52,19 +52,19 @@ class SAWGTest(unittest.TestCase): def test_make_events(self): d = self.driver d.offset.set(.9) - delay_mu(2*8) + delay_mu(2) d.frequency0.set64(.1) - delay_mu(2*8) + delay_mu(2) d.offset.set(0) self.assertEqual( self.rtio_manager.outputs, [ (0, 1, 0, int(round( (1 << self.driver.offset.width - 1)*.9))), - (2*8, 8, 0, [int(round( + (2, 8, 0, [int(round( (1 << self.driver.frequency0.width) / - self.channel.parallelism*d.core.coarse_ref_period*.1)), + self.channel.parallelism*.1)), 0]), - (4*8, 1, 0, 0), + (4, 1, 0, 0), ]) def run_channel(self, events): @@ -83,6 +83,7 @@ class SAWGTest(unittest.TestCase): yield rt.data.eq(int(data)) yield rt.stb.eq(1) assert not (yield rt.busy) + # print("{}: set ch {} to {}".format(time, channel, hex(data))) def log(dut, data, n): for i in range(dut.latency): @@ -92,15 +93,16 @@ class SAWGTest(unittest.TestCase): data.append((yield from [(yield _) for _ in dut.o])) data = [] + # print(int(events[-1][0]) + 1) mg.run_simulation(self.channel, [ gen(self.channel, events), - log(self.channel, data, int(events[-1][0]//8) + 1)], + log(self.channel, data, int(events[-1][0]) + 1)], vcd_name="dds.vcd") - return sum(data, []) + return data def test_run_channel(self): self.test_make_events() - out = self.run_channel(self.rtio_manager.outputs) + self.run_channel(self.rtio_manager.outputs) def test_coeff(self): import struct @@ -131,15 +133,15 @@ class SAWGTest(unittest.TestCase): def test_linear(self): d = self.driver d.offset.set_coeff_mu([100, 10]) - delay_mu(10*8) + delay_mu(10) d.offset.set_coeff([0]) - delay_mu(1*8) + delay_mu(1) out = self.run_channel(self.rtio_manager.outputs) - for i in range(len(out)//2): + for i in range(len(out) - 1): with self.subTest(i): v = 100 + i*10 - self.assertEqual(out[2*i], v) - self.assertEqual(out[2*i+1], v) + self.assertEqual(out[i], [v, v]) + self.assertEqual(out[-1], [0, 0]) def pack(self, v): n = len(v) @@ -168,24 +170,63 @@ class SAWGTest(unittest.TestCase): def test_smooth_linear(self): ch = self.driver.offset - ch.smooth(.1, .2, 13*ch.core.coarse_ref_period, 1) + ch.smooth(.1, .2, 13, 1) ch.set(.2) - delay_mu(1*8) + delay_mu(1) out = self.run_channel(self.rtio_manager.outputs) a = int(round(.1*ch.scale)) da = a//13 - for i in range(len(out)//2): + for i in range(len(out) - 1): with self.subTest(i): v = a + i*da - self.assertEqual(out[2*i], v) - self.assertEqual(out[2*i+1], v) + self.assertEqual(out[i], [v, v]) + a = int(round(.2*ch.scale)) + self.assertEqual(out[-1], [a, a]) def test_smooth_cubic(self): ch = self.driver.offset - ch.smooth(.1, .2, 13*ch.core.coarse_ref_period, 3) + ch.smooth(.1, .2, 13, 3) ch.set(.2) - delay_mu(1*8) + delay_mu(1) out = self.run_channel(self.rtio_manager.outputs) + out = sum(out, []) + # import matplotlib.pyplot as plt + # plt.plot(out) + # plt.show() + + @unittest.skip("needs sim.time.TimeManager tweak for timeline jumps") + def test_demo_2tone(self): + MHz = 1e-3 + ns = 1. + self.sawg0 = self.driver + + t_up = t_hold = t_down = 400*ns + a1 = .3 + a2 = .4 + order = 3 + + self.sawg0.frequency0.set(10*MHz) + self.sawg0.phase0.set(0.) + self.sawg0.frequency1.set64(1*MHz) + self.sawg0.phase1.set(0.) + self.sawg0.frequency2.set64(13*MHz) + self.sawg0.phase2.set(0.) + t = now_mu() + self.sawg0.amplitude1.smooth(.0, a1, t_up, order) + at_mu(t) + self.sawg0.amplitude2.smooth(.0, a2, t_up, order) + self.sawg0.amplitude1.set(a1) + self.sawg0.amplitude2.set(a2) + delay(t_hold) + t = now_mu() + self.sawg0.amplitude1.smooth(a1, .0, t_down, order) + at_mu(t) + self.sawg0.amplitude2.smooth(a2, .0, t_down, order) + self.sawg0.amplitude1.set(.0) + self.sawg0.amplitude2.set(.0) + + out = self.run_channel(self.rtio_manager.outputs) + out = sum(out, []) # import matplotlib.pyplot as plt # plt.plot(out) # plt.show() From fb58f31c9d0cb4d1c3eeae7fe854b79dd13216da Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 20:56:04 +0100 Subject: [PATCH 133/157] Revert "sawg: test w/o discrete_compensate" This reverts commit b736dd0df72ddcd93b81d232650e1e26389432e0. --- artiq/coredevice/sawg.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 89b4d7fd2..8bfe4edf9 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -88,7 +88,6 @@ class Spline: ci = int64(round(vi)) coeff64[i] = ci # artiq.wavesynth.coefficients.discrete_compensate: - continue if i == 2: coeff64[1] += ci >> self.time_width + 1 elif i == 3: From ed6d1e73ccc62e0429ecc78571c5cd4ff80a90bf Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 29 Nov 2016 23:16:32 +0100 Subject: [PATCH 134/157] sawg: cleanup --- artiq/coredevice/sawg.py | 60 ++++++++++++++++++----------- artiq/test/gateware/test_sawg_fe.py | 54 ++++++++++---------------- 2 files changed, 59 insertions(+), 55 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 8bfe4edf9..b508b6fcd 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -1,7 +1,7 @@ from numpy import int32, int64 from artiq.language.core import kernel, now_mu, portable, delay from artiq.coredevice.rtio import rtio_output, rtio_output_wide -from artiq.language.types import TInt32, TInt64, TFloat, TList +from artiq.language.types import TInt32, TInt64, TFloat class Spline: @@ -44,18 +44,18 @@ class Spline: """ rtio_output(now_mu(), self.channel, 0, self.to_mu(value)) - @kernel + @kernel(flags={"fast-math"}) def set64(self, value: TFloat): """Set spline value. :param value: Spline value relative to full-scale. """ - v = self.to_mu64(value) - l = [int32(v), int32(v >> 32)] + l = [int32(0)] * 2 + self.pack_coeff_mu([self.to_mu64(value)], l) rtio_output_wide(now_mu(), self.channel, 0, l) @kernel - def set_coeff_mu(self, value): + def set_coeff_mu(self, value): # TList(TInt32) """Set spline raw values. :param value: Spline packed raw values. @@ -63,7 +63,7 @@ class Spline: rtio_output_wide(now_mu(), self.channel, 0, value) @portable(flags={"fast-math"}) - def pack_coeff_mu(self, coeff, packed): + def pack_coeff_mu(self, coeff, packed): # TList(TInt64), TList(TInt32) pos = 0 for i in range(len(coeff)): wi = self.width + i*self.time_width @@ -74,13 +74,16 @@ class Spline: avail = 32 - used if avail > wi: avail = wi - packed[j] |= int32(ci & ((1 << avail) - 1)) << used + cij = int32(ci) + if avail != 32: + cij &= (1 << avail) - 1 + packed[j] |= cij << used ci >>= avail wi -= avail pos += avail @portable(flags={"fast-math"}) - def coeff_to_mu(self, coeff, coeff64): + def coeff_to_mu(self, coeff, coeff64): # TList(TFloat), TList(TInt64) for i in range(len(coeff)): vi = coeff[i] * self.scale for j in range(i): @@ -94,18 +97,31 @@ class Spline: coeff64[2] += ci >> self.time_width coeff64[1] += ci // 6 >> 2*self.time_width - @kernel - def set_coeff(self, value): + def coeff_as_packed_mu(self, coeff64): + n = len(coeff64) + width = n*self.width + (n - 1)*n//2*self.time_width + packed = [int32(0)] * ((width + 31)//32) + self.pack_coeff_mu(coeff64, packed) + return packed + + def coeff_as_packed(self, coeff): + coeff64 = [int64(0)] * len(coeff) + self.coeff_to_mu(coeff, coeff64) + return self.coeff_as_packed_mu(coeff64) + + @kernel(flags={"fast-math"}) + def set_coeff(self, coeff): # TList(TFloat) """Set spline coefficients. :param value: List of floating point spline knot coefficients, - lowest order (constant) coefficient first. + lowest order (constant) coefficient first. Units are the + unit of this spline's value times increasing powers of 1/s. """ - n = len(value) - width = n*self.width + (n - 1)*n//2*self.time_width + n = len(coeff) coeff64 = [int64(0)] * n + self.coeff_to_mu(coeff, coeff64) + width = n*self.width + (n - 1)*n//2*self.time_width packed = [int32(0)] * ((width + 31)//32) - self.coeff_to_mu(value, coeff64) self.pack_coeff_mu(coeff64, packed) self.set_coeff_mu(packed) @@ -132,15 +148,15 @@ class Spline: and 3 are valid: step, linear, cubic. """ if order == 0: - delay(duration/2) + delay(duration/2.) self.set_coeff([stop]) - delay(duration/2) + delay(duration/2.) elif order == 1: self.set_coeff([start, (stop - start)/duration]) delay(duration) elif order == 3: - v2 = 6*(stop - start)/(duration*duration) - self.set_coeff([start, 0., v2, -2*v2/duration]) + v2 = 6.*(stop - start)/(duration*duration) + self.set_coeff([start, 0., v2, -2.*v2/duration]) delay(duration) else: raise ValueError("Invalid interpolation order. " @@ -153,14 +169,14 @@ class SAWG: oscillators = exp(2j*pi*(frequency0*t + phase0))*( amplitude1*exp(2j*pi*(frequency1*t + phase1)) + - amplitude2*exp(2j*pi*(frequency2*t + phase2)) + amplitude2*exp(2j*pi*(frequency2*t + phase2))) output = (offset + i_enable*Re(oscillators) + q_enable*Im(buddy_oscillators)) Where: - * offset, amplitude1, amplitude1: in units of full scale + * offset, amplitude1, amplitude2: in units of full scale * phase0, phase1, phase2: in units of turns * frequency0, frequency1, frequency2: in units of Hz @@ -184,13 +200,13 @@ class SAWG: self.amplitude1 = Spline(width, time_width, channel_base + 2, self.core, 1/(2*cordic_gain**2)) self.frequency1 = Spline(3*width, time_width, channel_base + 3, - self.core, 1/self.core.coarse_ref_period) + self.core, self.core.coarse_ref_period) self.phase1 = Spline(width, time_width, channel_base + 4, self.core, 1.) self.amplitude2 = Spline(width, time_width, channel_base + 5, self.core, 1/(2*cordic_gain**2)) self.frequency2 = Spline(3*width, time_width, channel_base + 6, - self.core, 1/self.core.coarse_ref_period) + self.core, self.core.coarse_ref_period) self.phase2 = Spline(width, time_width, channel_base + 7, self.core, 1.) self.frequency0 = Spline(2*width, time_width, channel_base + 8, diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py index 8c90df3f6..5efbfa329 100644 --- a/artiq/test/gateware/test_sawg_fe.py +++ b/artiq/test/gateware/test_sawg_fe.py @@ -110,13 +110,9 @@ class SAWGTest(unittest.TestCase): # [.1, .01, -.00001], [.1, .01, .00001, -.000000001] for v in [-.1], [.1, -.01]: ch = self.driver.offset - q = [0] * len(v) - ch.coeff_to_mu(v, q) - n = len(v) + p = ch.coeff_as_packed(v) t = ch.time_width w = ch.width - p = [0] * ((n*w + (n - 1)*n//2*t + 31)//32) - ch.pack_coeff_mu(q, p) p = [_ & 0xffffffff for _ in p] p0 = [int(round(vi*ch.scale*ch.time_scale**i)) for i, vi in enumerate(v)] @@ -143,30 +139,19 @@ class SAWGTest(unittest.TestCase): self.assertEqual(out[i], [v, v]) self.assertEqual(out[-1], [0, 0]) - def pack(self, v): - n = len(v) - ch = self.driver.offset - t = ch.time_width - w = ch.width - p = [0] * ((n*w + (n - 1)*n//2*t + 31)//32) - ch.pack_coeff_mu(v, p) - p = [_ & 0xffffffff for _ in p] - return p - def test_pack(self): - self.assertEqual(self.pack([1]), [1]) - self.assertEqual(self.pack([1, 1 << 16]), [1, 1]) - self.assertEqual(self.pack([1, 1 << 32]), [1, 0]) - self.assertEqual(self.pack([0x1234, 0xa5a5a5a5]), + ch = self.driver.offset + self.assertEqual(ch.coeff_as_packed_mu([1]), [1]) + self.assertEqual(ch.coeff_as_packed_mu([1, 1 << 16]), [1, 1]) + self.assertEqual(ch.coeff_as_packed_mu([1, 1 << 32]), [1, 0]) + self.assertEqual(ch.coeff_as_packed_mu([0x1234, 0xa5a5a5a5]), [0xa5a51234, 0xa5a5]) - self.assertEqual(self.pack([1, 2, 3, 4]), + self.assertEqual(ch.coeff_as_packed_mu([1, 2, 3, 4]), [0x20001, 0x30000, 0, 4, 0]) - self.assertEqual(self.pack([-1, -2, -3, -4]), - [0xfffeffff, 0xfffdffff, 0xffffffff, - 0xfffffffc, 0xffffffff]) - self.assertEqual(self.pack([0, -1, 0, -1]), - [0xffff0000, 0x0000ffff, 0, - 0xffffffff, 0xffffffff]) + self.assertEqual(ch.coeff_as_packed_mu([-1, -2, -3, -4]), + [0xfffeffff, 0xfffdffff, -1, -4, -1]) + self.assertEqual(ch.coeff_as_packed_mu([0, -1, 0, -1]), + [0xffff0000, 0x0000ffff, 0, -1, -1]) def test_smooth_linear(self): ch = self.driver.offset @@ -190,11 +175,13 @@ class SAWGTest(unittest.TestCase): delay_mu(1) out = self.run_channel(self.rtio_manager.outputs) out = sum(out, []) - # import matplotlib.pyplot as plt - # plt.plot(out) - # plt.show() + if False: + import matplotlib.pyplot as plt + plt.plot(out) + plt.show() - @unittest.skip("needs sim.time.TimeManager tweak for timeline jumps") + # @unittest.skip("needs artiq.sim.time.TimeManager tweak for " + # "reverse timeline jumps") def test_demo_2tone(self): MHz = 1e-3 ns = 1. @@ -227,6 +214,7 @@ class SAWGTest(unittest.TestCase): out = self.run_channel(self.rtio_manager.outputs) out = sum(out, []) - # import matplotlib.pyplot as plt - # plt.plot(out) - # plt.show() + if True: + import matplotlib.pyplot as plt + plt.plot(out) + plt.show() From ea04fb2704820d31a4c484f78fa0c9ff22ed73bc Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 30 Nov 2016 11:02:41 +0100 Subject: [PATCH 135/157] test/sawg: skip 2tone demo test --- artiq/test/gateware/test_sawg_fe.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py index 5efbfa329..d18e1876d 100644 --- a/artiq/test/gateware/test_sawg_fe.py +++ b/artiq/test/gateware/test_sawg_fe.py @@ -180,8 +180,8 @@ class SAWGTest(unittest.TestCase): plt.plot(out) plt.show() - # @unittest.skip("needs artiq.sim.time.TimeManager tweak for " - # "reverse timeline jumps") + @unittest.skip("needs artiq.sim.time.TimeManager tweak for " + "reverse timeline jumps") def test_demo_2tone(self): MHz = 1e-3 ns = 1. From 01057dfb6dae4a5b724b352be66a0d39082a1fd3 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 30 Nov 2016 11:21:25 +0100 Subject: [PATCH 136/157] test/sawg: check 48 bit frequency --- artiq/test/gateware/test_sawg_fe.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py index d18e1876d..2cb41eb04 100644 --- a/artiq/test/gateware/test_sawg_fe.py +++ b/artiq/test/gateware/test_sawg_fe.py @@ -1,6 +1,7 @@ import unittest import migen as mg +from numpy import int32 from artiq.coredevice import sawg from artiq.language import (at_mu, now_mu, delay_mu, delay, @@ -54,17 +55,20 @@ class SAWGTest(unittest.TestCase): d.offset.set(.9) delay_mu(2) d.frequency0.set64(.1) + d.frequency1.set64(.1) delay_mu(2) d.offset.set(0) + v = int(round((1 << 48) * .1)) self.assertEqual( self.rtio_manager.outputs, [ - (0, 1, 0, int(round( + (0., 1, 0, int(round( (1 << self.driver.offset.width - 1)*.9))), - (2, 8, 0, [int(round( + (2., 8, 0, [int(round( (1 << self.driver.frequency0.width) / self.channel.parallelism*.1)), 0]), - (4, 1, 0, 0), + (2., 3, 0, [int32(v), int32(v >> 32)]), + (4., 1, 0, 0), ]) def run_channel(self, events): From 93a853a0e054dd4acc2b8a1e30008e352905a3fa Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 1 Dec 2016 16:00:06 +0100 Subject: [PATCH 137/157] test/sawg: non trivial coarse_ref_period --- artiq/test/gateware/test_sawg_fe.py | 38 +++++++++++++++-------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py index 2cb41eb04..7fd74a958 100644 --- a/artiq/test/gateware/test_sawg_fe.py +++ b/artiq/test/gateware/test_sawg_fe.py @@ -4,7 +4,7 @@ import migen as mg from numpy import int32 from artiq.coredevice import sawg -from artiq.language import (at_mu, now_mu, delay_mu, delay, +from artiq.language import (at_mu, now_mu, delay, core as core_language) from artiq.gateware.rtio.phy.sawg import Channel from artiq.sim import devices as sim_devices, time as sim_time @@ -38,7 +38,8 @@ class SAWGTest(unittest.TestCase): self.rtio_manager = RTIOManager() self.rtio_manager.patch(sawg) self.core = sim_devices.Core({}) - self.core.coarse_ref_period = 1 + self.core.coarse_ref_period = 6.66666 + self.t = self.core.coarse_ref_period self.channel = mg.ClockDomainsRenamer({"rio_phy": "sys"})( Channel(width=16, parallelism=2)) self.driver = sawg.SAWG({"core": self.core}, channel_base=0, @@ -53,28 +54,29 @@ class SAWGTest(unittest.TestCase): def test_make_events(self): d = self.driver d.offset.set(.9) - delay_mu(2) + delay(2*self.t) d.frequency0.set64(.1) d.frequency1.set64(.1) - delay_mu(2) + delay(2*self.t) d.offset.set(0) - v = int(round((1 << 48) * .1)) + v = int(round((1 << 48) * .1 * self.t)) self.assertEqual( self.rtio_manager.outputs, [ (0., 1, 0, int(round( (1 << self.driver.offset.width - 1)*.9))), - (2., 8, 0, [int(round( - (1 << self.driver.frequency0.width) / - self.channel.parallelism*.1)), + (2.*self.t, 8, 0, [int(round( + (1 << self.driver.frequency0.width) * + self.t/self.channel.parallelism*.1)), 0]), - (2., 3, 0, [int32(v), int32(v >> 32)]), - (4., 1, 0, 0), + (2.*self.t, 3, 0, [int32(v), int32(v >> 32)]), + (4.*self.t, 1, 0, 0), ]) def run_channel(self, events): def gen(dut, events): c = 0 for time, channel, address, data in events: + time //= self.t assert c <= time while c < time: yield @@ -100,7 +102,7 @@ class SAWGTest(unittest.TestCase): # print(int(events[-1][0]) + 1) mg.run_simulation(self.channel, [ gen(self.channel, events), - log(self.channel, data, int(events[-1][0]) + 1)], + log(self.channel, data, int(events[-1][0]//self.t) + 1)], vcd_name="dds.vcd") return data @@ -133,9 +135,9 @@ class SAWGTest(unittest.TestCase): def test_linear(self): d = self.driver d.offset.set_coeff_mu([100, 10]) - delay_mu(10) + delay(10*self.t) d.offset.set_coeff([0]) - delay_mu(1) + delay(1*self.t) out = self.run_channel(self.rtio_manager.outputs) for i in range(len(out) - 1): with self.subTest(i): @@ -159,15 +161,15 @@ class SAWGTest(unittest.TestCase): def test_smooth_linear(self): ch = self.driver.offset - ch.smooth(.1, .2, 13, 1) + ch.smooth(.1, .2, 13*self.t, 1) ch.set(.2) - delay_mu(1) + delay(1*self.t) out = self.run_channel(self.rtio_manager.outputs) a = int(round(.1*ch.scale)) - da = a//13 + da = int(round(.1*ch.scale*(1 << ch.width)//13)) for i in range(len(out) - 1): with self.subTest(i): - v = a + i*da + v = a + (i*da >> ch.width) self.assertEqual(out[i], [v, v]) a = int(round(.2*ch.scale)) self.assertEqual(out[-1], [a, a]) @@ -176,7 +178,7 @@ class SAWGTest(unittest.TestCase): ch = self.driver.offset ch.smooth(.1, .2, 13, 3) ch.set(.2) - delay_mu(1) + delay(1*self.t) out = self.run_channel(self.rtio_manager.outputs) out = sum(out, []) if False: From 6e9bc7c05d0568b430df7170ad106c47476ed405 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 1 Dec 2016 16:25:01 +0100 Subject: [PATCH 138/157] sawg: merge set/set64 --- artiq/coredevice/sawg.py | 19 +++++++------------ artiq/test/gateware/test_sawg_fe.py | 13 ++++++------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index b508b6fcd..91062e6a6 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -36,23 +36,18 @@ class Spline: """ rtio_output(now_mu(), self.channel, 0, value) - @kernel + @kernel(flags={"fast-math"}) def set(self, value: TFloat): """Set spline value. :param value: Spline value relative to full-scale. """ - rtio_output(now_mu(), self.channel, 0, self.to_mu(value)) - - @kernel(flags={"fast-math"}) - def set64(self, value: TFloat): - """Set spline value. - - :param value: Spline value relative to full-scale. - """ - l = [int32(0)] * 2 - self.pack_coeff_mu([self.to_mu64(value)], l) - rtio_output_wide(now_mu(), self.channel, 0, l) + if self.width > 32: + l = [int32(0)] * 2 + self.pack_coeff_mu([self.to_mu64(value)], l) + rtio_output_wide(now_mu(), self.channel, 0, l) + else: + rtio_output(now_mu(), self.channel, 0, self.to_mu(value)) @kernel def set_coeff_mu(self, value): # TList(TInt32) diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py index 7fd74a958..c7272f267 100644 --- a/artiq/test/gateware/test_sawg_fe.py +++ b/artiq/test/gateware/test_sawg_fe.py @@ -55,8 +55,8 @@ class SAWGTest(unittest.TestCase): d = self.driver d.offset.set(.9) delay(2*self.t) - d.frequency0.set64(.1) - d.frequency1.set64(.1) + d.frequency0.set(.1) + d.frequency1.set(.1) delay(2*self.t) d.offset.set(0) v = int(round((1 << 48) * .1 * self.t)) @@ -64,10 +64,9 @@ class SAWGTest(unittest.TestCase): self.rtio_manager.outputs, [ (0., 1, 0, int(round( (1 << self.driver.offset.width - 1)*.9))), - (2.*self.t, 8, 0, [int(round( + (2.*self.t, 8, 0, int(round( (1 << self.driver.frequency0.width) * - self.t/self.channel.parallelism*.1)), - 0]), + self.t/self.channel.parallelism*.1))), (2.*self.t, 3, 0, [int32(v), int32(v >> 32)]), (4.*self.t, 1, 0, 0), ]) @@ -200,9 +199,9 @@ class SAWGTest(unittest.TestCase): self.sawg0.frequency0.set(10*MHz) self.sawg0.phase0.set(0.) - self.sawg0.frequency1.set64(1*MHz) + self.sawg0.frequency1.set(1*MHz) self.sawg0.phase1.set(0.) - self.sawg0.frequency2.set64(13*MHz) + self.sawg0.frequency2.set(13*MHz) self.sawg0.phase2.set(0.) t = now_mu() self.sawg0.amplitude1.smooth(.0, a1, t_up, order) From 3cee269afe0b22fe9d5e80eab5dfff9a49555dde Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 2 Dec 2016 11:06:45 +0800 Subject: [PATCH 139/157] phaser: fix typo --- artiq/gateware/phaser.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/phaser.py b/artiq/gateware/phaser.py index ca6185764..29df93031 100644 --- a/artiq/gateware/phaser.py +++ b/artiq/gateware/phaser.py @@ -39,35 +39,35 @@ fmc_adapter_io = [ IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE"), ), - ("ad9154_jesd", 0, # AD9154's SERIND7 + ("ad9154_jesd", 0, # AD9154's SERDIN7 Subsignal("txp", Pins("HPC:DP0_C2M_P")), Subsignal("txn", Pins("HPC:DP0_C2M_N")) ), - ("ad9154_jesd", 1, # AD9154's SERIND6 + ("ad9154_jesd", 1, # AD9154's SERDIN6 Subsignal("txp", Pins("HPC:DP1_C2M_P")), Subsignal("txn", Pins("HPC:DP1_C2M_N")) ), - ("ad9154_jesd", 2, # AD9154's SERIND5 + ("ad9154_jesd", 2, # AD9154's SERDIN5 Subsignal("txp", Pins("HPC:DP2_C2M_P")), Subsignal("txn", Pins("HPC:DP2_C2M_N")) ), - ("ad9154_jesd", 3, # AD9154's SERIND4 + ("ad9154_jesd", 3, # AD9154's SERDIN4 Subsignal("txp", Pins("HPC:DP3_C2M_P")), Subsignal("txn", Pins("HPC:DP3_C2M_N")) ), - ("ad9154_jesd", 4, # AD9154's SERIND2 + ("ad9154_jesd", 4, # AD9154's SERDIN2 Subsignal("txp", Pins("HPC:DP4_C2M_P")), Subsignal("txn", Pins("HPC:DP4_C2M_N")) ), - ("ad9154_jesd", 5, # AD9154's SERIND0 + ("ad9154_jesd", 5, # AD9154's SERDIN0 Subsignal("txp", Pins("HPC:DP5_C2M_P")), Subsignal("txn", Pins("HPC:DP5_C2M_N")) ), - ("ad9154_jesd", 6, # AD9154's SERIND1 + ("ad9154_jesd", 6, # AD9154's SERDIN1 Subsignal("txp", Pins("HPC:DP6_C2M_P")), Subsignal("txn", Pins("HPC:DP6_C2M_N")) ), - ("ad9154_jesd", 7, # AD9154's SERIND3 + ("ad9154_jesd", 7, # AD9154's SERDIN3 Subsignal("txp", Pins("HPC:DP7_C2M_P")), Subsignal("txn", Pins("HPC:DP7_C2M_N")) ), From cbf1004df334432dedd93753bf32681a3a2f4fe9 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 2 Dec 2016 10:31:59 +0100 Subject: [PATCH 140/157] gateware/phaser -> gateware/ad9154_fmc_ebz --- artiq/gateware/{phaser.py => ad9154_fmc_ebz.py} | 2 +- artiq/gateware/targets/phaser.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename artiq/gateware/{phaser.py => ad9154_fmc_ebz.py} (99%) diff --git a/artiq/gateware/phaser.py b/artiq/gateware/ad9154_fmc_ebz.py similarity index 99% rename from artiq/gateware/phaser.py rename to artiq/gateware/ad9154_fmc_ebz.py index ca6185764..f9826ade6 100644 --- a/artiq/gateware/phaser.py +++ b/artiq/gateware/ad9154_fmc_ebz.py @@ -1,7 +1,7 @@ from migen.build.generic_platform import * -fmc_adapter_io = [ +ad9154_fmc_ebz = [ ("ad9154_spi", 0, # AD9154 should give control of SPI to FMC when USB cable is unplugged, # It's the case, but the PIC18F24J50 is introducing noise on SPI SCK diff --git a/artiq/gateware/targets/phaser.py b/artiq/gateware/targets/phaser.py index 6208ef5c6..df383b40d 100755 --- a/artiq/gateware/targets/phaser.py +++ b/artiq/gateware/targets/phaser.py @@ -23,7 +23,7 @@ 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.phaser import fmc_adapter_io +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 @@ -173,7 +173,7 @@ class Phaser(MiniSoC, AMPSoC): ]) platform = self.platform - platform.add_extension(fmc_adapter_io) + platform.add_extension(ad9154_fmc_ebz) self.submodules.leds = gpio.GPIOOut(Cat( platform.request("user_led", 0), From 87bd2072e8698aa9777739cf3993fa0efd519dd4 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 2 Dec 2016 14:33:26 +0100 Subject: [PATCH 141/157] sawg: round to int64 --- artiq/coredevice/sawg.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 91062e6a6..2b4feff98 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -12,9 +12,10 @@ class Spline: self.core = core_device self.channel = channel self.width = width - self.scale = (1 << width) * scale + self.scale = float((int64(1) << width) * scale) self.time_width = time_width - self.time_scale = (1 << time_width) * core_device.coarse_ref_period + self.time_scale = float((1 << time_width) * + core_device.coarse_ref_period) @portable(flags={"fast-math"}) def to_mu(self, value: TFloat) -> TInt32: From d6f6ebf0668e22ce46fd6d3dc253500628e0790d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 2 Dec 2016 18:18:47 +0100 Subject: [PATCH 142/157] sawg: demo_2tone --- .../examples/phaser/repository/demo_2tone.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 artiq/examples/phaser/repository/demo_2tone.py diff --git a/artiq/examples/phaser/repository/demo_2tone.py b/artiq/examples/phaser/repository/demo_2tone.py new file mode 100644 index 000000000..5bcfe9962 --- /dev/null +++ b/artiq/examples/phaser/repository/demo_2tone.py @@ -0,0 +1,46 @@ +from artiq.experiment import * + + +class SAWGTest(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("led") + self.setattr_device("ttl_sma") + + self.setattr_device("sawg0") + self.setattr_device("sawg1") + self.setattr_device("sawg2") + self.setattr_device("sawg3") + + @kernel + def run(self): + self.core.break_realtime() + self.ttl_sma.output() + + while True: + t_up = t_hold = t_down = 800*ns + a1 = .3 + a2 = .4 + order = 3 + + delay(20*ms) + self.sawg0.frequency0.set(10*MHz) + self.sawg0.phase0.set(0.) + self.sawg0.frequency1.set(1*MHz) + self.sawg0.phase1.set(0.) + self.sawg0.frequency2.set(9*MHz) + self.sawg0.phase2.set(0.) + with parallel: + self.sawg0.amplitude1.smooth(.0, a1, t_up, order) + self.sawg0.amplitude2.smooth(.0, a2, t_up, order) + self.sawg0.amplitude1.set(a1) + self.sawg0.amplitude2.set(a2) + delay(t_hold) + with parallel: + self.sawg0.amplitude1.smooth(a1, .0, t_down, order) + self.sawg0.amplitude2.smooth(a2, .0, t_down, order) + self.sawg0.amplitude1.set(.0) + self.sawg0.amplitude2.set(.0) + + self.sawg1.amplitude1.set(.0) + self.sawg1.amplitude2.set(.0) From 39becd0b4e1d0cc0321dbeb028dca5f76670f55a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 4 Dec 2016 16:50:49 +0100 Subject: [PATCH 143/157] sawg: document --- artiq/coredevice/sawg.py | 68 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 2b4feff98..df1e34c93 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -5,6 +5,18 @@ from artiq.language.types import TInt32, TInt64, TFloat class Spline: + """Spline interpolating RTIO channel. + + One knot of a polynomial basis spline (B-spline) :math:`u(t)` + is defined by the coefficients :math:`u_n` up to order :math:`n = k`. + If the knot is evaluated starting at time :math:`t_0`, the output + :math:`u(t)` for :math:`t > t_0, t_0` is: + + .. math:: + u(t) = \sum_{n=0}^k \frac{u_n}{n!} (t - t_0)^n + = u_0 + u_1 (t - t_0) + \frac{u_2}{2} (t - t_0)^2 + \dots + """ + kernel_invariants = {"channel", "core", "scale", "width", "time_width", "time_scale"} @@ -19,14 +31,20 @@ class Spline: @portable(flags={"fast-math"}) def to_mu(self, value: TFloat) -> TInt32: + """Convert floating point `value` from physical units to 32 bit + integer machine units.""" return int32(round(value*self.scale)) @portable(flags={"fast-math"}) def from_mu(self, value: TInt32) -> TFloat: + """Convert 32 bit integer `value` from machine units to floating point + physical units.""" return value/self.scale @portable(flags={"fast-math"}) def to_mu64(self, value: TFloat) -> TInt64: + """Convert floating point `value` from physical units to 64 bit + integer machine units.""" return int64(round(value*self.scale)) @kernel @@ -60,6 +78,15 @@ class Spline: @portable(flags={"fast-math"}) def pack_coeff_mu(self, coeff, packed): # TList(TInt64), TList(TInt32) + """Pack coefficients into RTIO data + + :param coeff: TList(TInt64) list of machine units spline coefficients. + Lowest (zeroth) order first. The coefficient list is zero-extended + by the RTIO gateware. + :param packed: TList(TInt32) list for packed RTIO data. Must be + pre-allocated. Length in bits is + `n*width + (n - 1)*n//2*time_width` + """ pos = 0 for i in range(len(coeff)): wi = self.width + i*self.time_width @@ -80,6 +107,13 @@ class Spline: @portable(flags={"fast-math"}) def coeff_to_mu(self, coeff, coeff64): # TList(TFloat), TList(TInt64) + """Convert a floating point list of coefficients into a 64 bit + integer (preallocated). + + :param coeff: TList(TFloat) list of coefficients in physical units. + :param coeff64: TList(TInt64) preallocated list of coefficients in + machine units. + """ for i in range(len(coeff)): vi = coeff[i] * self.scale for j in range(i): @@ -94,6 +128,12 @@ class Spline: coeff64[1] += ci // 6 >> 2*self.time_width def coeff_as_packed_mu(self, coeff64): + """Pack 64 bit integer machine units coefficients into 32 bit integer + RTIO data list. + + This is a host-only method that can be used to generate packed + spline knot data to be frozen into kernels at compile time. + """ n = len(coeff64) width = n*self.width + (n - 1)*n//2*self.time_width packed = [int32(0)] * ((width + 31)//32) @@ -101,6 +141,12 @@ class Spline: return packed def coeff_as_packed(self, coeff): + """Convert floating point spline coefficients into 32 bit integer + packed data. + + This is a host-only method that can be used to generate packed + spline knot data to be frozen into kernels at compile time. + """ coeff64 = [int64(0)] * len(coeff) self.coeff_to_mu(coeff, coeff64) return self.coeff_as_packed_mu(coeff64) @@ -109,6 +155,12 @@ class Spline: def set_coeff(self, coeff): # TList(TFloat) """Set spline coefficients. + Missing coefficients (high order) are zero-extended byt the RTIO + gateware. + + If more coefficients are supplied than the gateware supports the extra + coefficients are ignored. + :param value: List of floating point spline knot coefficients, lowest order (constant) coefficient first. Units are the unit of this spline's value times increasing powers of 1/s. @@ -126,10 +178,14 @@ class Spline: order: TInt32): """Initiate an interpolated value change. - The third order interpolation is constrained to have zero first - order derivative at both start and stop. + For zeroth order (step) interpolation, the step is at + `start + duration/2`. - For zeroth order (step) interpolation, the step is at duration/2. + First order interpolation corresponds to a linear value ramp from + `start` to `stop` over `duration`. + + The third order interpolation is constrained to have zero first + order derivative at both `start` and `stop`. For first order and third order interpolation (linear and cubic) the interpolator needs to be stopped (or fed a new spline knot) @@ -137,9 +193,9 @@ class Spline: This method advances the timeline by `duration`. - :param start: Initial value of the change. - :param stop: Final value of the change. - :param duration: Duration of the interpolation. + :param start: Initial value of the change. In physical units. + :param stop: Final value of the change. In physical units. + :param duration: Duration of the interpolation. In physical units. :param order: Order of the interpolation. Only 0, 1, and 3 are valid: step, linear, cubic. """ From 695eb705b35b50c6908edd7de8d0c97b48778c66 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 4 Dec 2016 16:52:08 +0100 Subject: [PATCH 144/157] sawg: extract spline --- artiq/coredevice/sawg.py | 216 +------------------------------------ artiq/coredevice/spline.py | 215 ++++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 215 deletions(-) create mode 100644 artiq/coredevice/spline.py diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index df1e34c93..319bf781c 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -1,218 +1,4 @@ -from numpy import int32, int64 -from artiq.language.core import kernel, now_mu, portable, delay -from artiq.coredevice.rtio import rtio_output, rtio_output_wide -from artiq.language.types import TInt32, TInt64, TFloat - - -class Spline: - """Spline interpolating RTIO channel. - - One knot of a polynomial basis spline (B-spline) :math:`u(t)` - is defined by the coefficients :math:`u_n` up to order :math:`n = k`. - If the knot is evaluated starting at time :math:`t_0`, the output - :math:`u(t)` for :math:`t > t_0, t_0` is: - - .. math:: - u(t) = \sum_{n=0}^k \frac{u_n}{n!} (t - t_0)^n - = u_0 + u_1 (t - t_0) + \frac{u_2}{2} (t - t_0)^2 + \dots - """ - - kernel_invariants = {"channel", "core", "scale", "width", - "time_width", "time_scale"} - - def __init__(self, width, time_width, channel, core_device, scale=1.): - self.core = core_device - self.channel = channel - self.width = width - self.scale = float((int64(1) << width) * scale) - self.time_width = time_width - self.time_scale = float((1 << time_width) * - core_device.coarse_ref_period) - - @portable(flags={"fast-math"}) - def to_mu(self, value: TFloat) -> TInt32: - """Convert floating point `value` from physical units to 32 bit - integer machine units.""" - return int32(round(value*self.scale)) - - @portable(flags={"fast-math"}) - def from_mu(self, value: TInt32) -> TFloat: - """Convert 32 bit integer `value` from machine units to floating point - physical units.""" - return value/self.scale - - @portable(flags={"fast-math"}) - def to_mu64(self, value: TFloat) -> TInt64: - """Convert floating point `value` from physical units to 64 bit - integer machine units.""" - return int64(round(value*self.scale)) - - @kernel - def set_mu(self, value: TInt32): - """Set spline value (machine units). - - :param value: Spline value in integer machine units. - """ - rtio_output(now_mu(), self.channel, 0, value) - - @kernel(flags={"fast-math"}) - def set(self, value: TFloat): - """Set spline value. - - :param value: Spline value relative to full-scale. - """ - if self.width > 32: - l = [int32(0)] * 2 - self.pack_coeff_mu([self.to_mu64(value)], l) - rtio_output_wide(now_mu(), self.channel, 0, l) - else: - rtio_output(now_mu(), self.channel, 0, self.to_mu(value)) - - @kernel - def set_coeff_mu(self, value): # TList(TInt32) - """Set spline raw values. - - :param value: Spline packed raw values. - """ - rtio_output_wide(now_mu(), self.channel, 0, value) - - @portable(flags={"fast-math"}) - def pack_coeff_mu(self, coeff, packed): # TList(TInt64), TList(TInt32) - """Pack coefficients into RTIO data - - :param coeff: TList(TInt64) list of machine units spline coefficients. - Lowest (zeroth) order first. The coefficient list is zero-extended - by the RTIO gateware. - :param packed: TList(TInt32) list for packed RTIO data. Must be - pre-allocated. Length in bits is - `n*width + (n - 1)*n//2*time_width` - """ - pos = 0 - for i in range(len(coeff)): - wi = self.width + i*self.time_width - ci = coeff[i] - while wi != 0: - j = pos//32 - used = pos - 32*j - avail = 32 - used - if avail > wi: - avail = wi - cij = int32(ci) - if avail != 32: - cij &= (1 << avail) - 1 - packed[j] |= cij << used - ci >>= avail - wi -= avail - pos += avail - - @portable(flags={"fast-math"}) - def coeff_to_mu(self, coeff, coeff64): # TList(TFloat), TList(TInt64) - """Convert a floating point list of coefficients into a 64 bit - integer (preallocated). - - :param coeff: TList(TFloat) list of coefficients in physical units. - :param coeff64: TList(TInt64) preallocated list of coefficients in - machine units. - """ - for i in range(len(coeff)): - vi = coeff[i] * self.scale - for j in range(i): - vi *= self.time_scale - ci = int64(round(vi)) - coeff64[i] = ci - # artiq.wavesynth.coefficients.discrete_compensate: - if i == 2: - coeff64[1] += ci >> self.time_width + 1 - elif i == 3: - coeff64[2] += ci >> self.time_width - coeff64[1] += ci // 6 >> 2*self.time_width - - def coeff_as_packed_mu(self, coeff64): - """Pack 64 bit integer machine units coefficients into 32 bit integer - RTIO data list. - - This is a host-only method that can be used to generate packed - spline knot data to be frozen into kernels at compile time. - """ - n = len(coeff64) - width = n*self.width + (n - 1)*n//2*self.time_width - packed = [int32(0)] * ((width + 31)//32) - self.pack_coeff_mu(coeff64, packed) - return packed - - def coeff_as_packed(self, coeff): - """Convert floating point spline coefficients into 32 bit integer - packed data. - - This is a host-only method that can be used to generate packed - spline knot data to be frozen into kernels at compile time. - """ - coeff64 = [int64(0)] * len(coeff) - self.coeff_to_mu(coeff, coeff64) - return self.coeff_as_packed_mu(coeff64) - - @kernel(flags={"fast-math"}) - def set_coeff(self, coeff): # TList(TFloat) - """Set spline coefficients. - - Missing coefficients (high order) are zero-extended byt the RTIO - gateware. - - If more coefficients are supplied than the gateware supports the extra - coefficients are ignored. - - :param value: List of floating point spline knot coefficients, - lowest order (constant) coefficient first. Units are the - unit of this spline's value times increasing powers of 1/s. - """ - n = len(coeff) - coeff64 = [int64(0)] * n - self.coeff_to_mu(coeff, coeff64) - width = n*self.width + (n - 1)*n//2*self.time_width - packed = [int32(0)] * ((width + 31)//32) - self.pack_coeff_mu(coeff64, packed) - self.set_coeff_mu(packed) - - @kernel(flags={"fast-math"}) - def smooth(self, start: TFloat, stop: TFloat, duration: TFloat, - order: TInt32): - """Initiate an interpolated value change. - - For zeroth order (step) interpolation, the step is at - `start + duration/2`. - - First order interpolation corresponds to a linear value ramp from - `start` to `stop` over `duration`. - - The third order interpolation is constrained to have zero first - order derivative at both `start` and `stop`. - - For first order and third order interpolation (linear and cubic) - the interpolator needs to be stopped (or fed a new spline knot) - explicitly at the stop time. - - This method advances the timeline by `duration`. - - :param start: Initial value of the change. In physical units. - :param stop: Final value of the change. In physical units. - :param duration: Duration of the interpolation. In physical units. - :param order: Order of the interpolation. Only 0, 1, - and 3 are valid: step, linear, cubic. - """ - if order == 0: - delay(duration/2.) - self.set_coeff([stop]) - delay(duration/2.) - elif order == 1: - self.set_coeff([start, (stop - start)/duration]) - delay(duration) - elif order == 3: - v2 = 6.*(stop - start)/(duration*duration) - self.set_coeff([start, 0., v2, -2.*v2/duration]) - delay(duration) - else: - raise ValueError("Invalid interpolation order. " - "Supported orders are: 0, 1, 3.") +from artiq.coredevice.spline import Spline class SAWG: diff --git a/artiq/coredevice/spline.py b/artiq/coredevice/spline.py new file mode 100644 index 000000000..a6c99ddd9 --- /dev/null +++ b/artiq/coredevice/spline.py @@ -0,0 +1,215 @@ +from numpy import int32, int64 +from artiq.language.core import kernel, now_mu, portable, delay +from artiq.coredevice.rtio import rtio_output, rtio_output_wide +from artiq.language.types import TInt32, TInt64, TFloat + + +class Spline: + """Spline interpolating RTIO channel. + + One knot of a polynomial basis spline (B-spline) :math:`u(t)` + is defined by the coefficients :math:`u_n` up to order :math:`n = k`. + If the knot is evaluated starting at time :math:`t_0`, the output + :math:`u(t)` for :math:`t > t_0, t_0` is: + + .. math:: + u(t) = \sum_{n=0}^k \frac{u_n}{n!} (t - t_0)^n + = u_0 + u_1 (t - t_0) + \frac{u_2}{2} (t - t_0)^2 + \dots + """ + + kernel_invariants = {"channel", "core", "scale", "width", + "time_width", "time_scale"} + + def __init__(self, width, time_width, channel, core_device, scale=1.): + self.core = core_device + self.channel = channel + self.width = width + self.scale = float((int64(1) << width) * scale) + self.time_width = time_width + self.time_scale = float((1 << time_width) * + core_device.coarse_ref_period) + + @portable(flags={"fast-math"}) + def to_mu(self, value: TFloat) -> TInt32: + """Convert floating point `value` from physical units to 32 bit + integer machine units.""" + return int32(round(value*self.scale)) + + @portable(flags={"fast-math"}) + def from_mu(self, value: TInt32) -> TFloat: + """Convert 32 bit integer `value` from machine units to floating point + physical units.""" + return value/self.scale + + @portable(flags={"fast-math"}) + def to_mu64(self, value: TFloat) -> TInt64: + """Convert floating point `value` from physical units to 64 bit + integer machine units.""" + return int64(round(value*self.scale)) + + @kernel + def set_mu(self, value: TInt32): + """Set spline value (machine units). + + :param value: Spline value in integer machine units. + """ + rtio_output(now_mu(), self.channel, 0, value) + + @kernel(flags={"fast-math"}) + def set(self, value: TFloat): + """Set spline value. + + :param value: Spline value relative to full-scale. + """ + if self.width > 32: + l = [int32(0)] * 2 + self.pack_coeff_mu([self.to_mu64(value)], l) + rtio_output_wide(now_mu(), self.channel, 0, l) + else: + rtio_output(now_mu(), self.channel, 0, self.to_mu(value)) + + @kernel + def set_coeff_mu(self, value): # TList(TInt32) + """Set spline raw values. + + :param value: Spline packed raw values. + """ + rtio_output_wide(now_mu(), self.channel, 0, value) + + @portable(flags={"fast-math"}) + def pack_coeff_mu(self, coeff, packed): # TList(TInt64), TList(TInt32) + """Pack coefficients into RTIO data + + :param coeff: TList(TInt64) list of machine units spline coefficients. + Lowest (zeroth) order first. The coefficient list is zero-extended + by the RTIO gateware. + :param packed: TList(TInt32) list for packed RTIO data. Must be + pre-allocated. Length in bits is + `n*width + (n - 1)*n//2*time_width` + """ + pos = 0 + for i in range(len(coeff)): + wi = self.width + i*self.time_width + ci = coeff[i] + while wi != 0: + j = pos//32 + used = pos - 32*j + avail = 32 - used + if avail > wi: + avail = wi + cij = int32(ci) + if avail != 32: + cij &= (1 << avail) - 1 + packed[j] |= cij << used + ci >>= avail + wi -= avail + pos += avail + + @portable(flags={"fast-math"}) + def coeff_to_mu(self, coeff, coeff64): # TList(TFloat), TList(TInt64) + """Convert a floating point list of coefficients into a 64 bit + integer (preallocated). + + :param coeff: TList(TFloat) list of coefficients in physical units. + :param coeff64: TList(TInt64) preallocated list of coefficients in + machine units. + """ + for i in range(len(coeff)): + vi = coeff[i] * self.scale + for j in range(i): + vi *= self.time_scale + ci = int64(round(vi)) + coeff64[i] = ci + # artiq.wavesynth.coefficients.discrete_compensate: + if i == 2: + coeff64[1] += ci >> self.time_width + 1 + elif i == 3: + coeff64[2] += ci >> self.time_width + coeff64[1] += ci // 6 >> 2*self.time_width + + def coeff_as_packed_mu(self, coeff64): + """Pack 64 bit integer machine units coefficients into 32 bit integer + RTIO data list. + + This is a host-only method that can be used to generate packed + spline knot data to be frozen into kernels at compile time. + """ + n = len(coeff64) + width = n*self.width + (n - 1)*n//2*self.time_width + packed = [int32(0)] * ((width + 31)//32) + self.pack_coeff_mu(coeff64, packed) + return packed + + def coeff_as_packed(self, coeff): + """Convert floating point spline coefficients into 32 bit integer + packed data. + + This is a host-only method that can be used to generate packed + spline knot data to be frozen into kernels at compile time. + """ + coeff64 = [int64(0)] * len(coeff) + self.coeff_to_mu(coeff, coeff64) + return self.coeff_as_packed_mu(coeff64) + + @kernel(flags={"fast-math"}) + def set_coeff(self, coeff): # TList(TFloat) + """Set spline coefficients. + + Missing coefficients (high order) are zero-extended byt the RTIO + gateware. + + If more coefficients are supplied than the gateware supports the extra + coefficients are ignored. + + :param value: List of floating point spline knot coefficients, + lowest order (constant) coefficient first. Units are the + unit of this spline's value times increasing powers of 1/s. + """ + n = len(coeff) + coeff64 = [int64(0)] * n + self.coeff_to_mu(coeff, coeff64) + width = n*self.width + (n - 1)*n//2*self.time_width + packed = [int32(0)] * ((width + 31)//32) + self.pack_coeff_mu(coeff64, packed) + self.set_coeff_mu(packed) + + @kernel(flags={"fast-math"}) + def smooth(self, start: TFloat, stop: TFloat, duration: TFloat, + order: TInt32): + """Initiate an interpolated value change. + + For zeroth order (step) interpolation, the step is at + `start + duration/2`. + + First order interpolation corresponds to a linear value ramp from + `start` to `stop` over `duration`. + + The third order interpolation is constrained to have zero first + order derivative at both `start` and `stop`. + + For first order and third order interpolation (linear and cubic) + the interpolator needs to be stopped (or fed a new spline knot) + explicitly at the stop time. + + This method advances the timeline by `duration`. + + :param start: Initial value of the change. In physical units. + :param stop: Final value of the change. In physical units. + :param duration: Duration of the interpolation. In physical units. + :param order: Order of the interpolation. Only 0, 1, + and 3 are valid: step, linear, cubic. + """ + if order == 0: + delay(duration/2.) + self.set_coeff([stop]) + delay(duration/2.) + elif order == 1: + self.set_coeff([start, (stop - start)/duration]) + delay(duration) + elif order == 3: + v2 = 6.*(stop - start)/(duration*duration) + self.set_coeff([start, 0., v2, -2.*v2/duration]) + delay(duration) + else: + raise ValueError("Invalid interpolation order. " + "Supported orders are: 0, 1, 3.") From 5efd0fcea5c8f51b4f4d190ecf1b14bce8a4cf6d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 6 Dec 2016 19:25:40 +0100 Subject: [PATCH 145/157] sawg: documentation --- artiq/coredevice/sawg.py | 25 +++++++++++++++---------- artiq/coredevice/spline.py | 15 +++++++++++---- doc/manual/core_drivers_reference.rst | 12 +++++++++--- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 319bf781c..1010e48db 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -13,13 +13,18 @@ class SAWG: i_enable*Re(oscillators) + q_enable*Im(buddy_oscillators)) - Where: - * offset, amplitude1, amplitude2: in units of full scale - * phase0, phase1, phase2: in units of turns - * frequency0, frequency1, frequency2: in units of Hz + The nine spline interpolators are accessible as attributes: + + * :attr:`offset`, :attr:`amplitude1`, :attr:`amplitude2`: in units + of full scale + * :attr:`phase0`, :attr:`phase1`, :attr:`phase2`: in units of turns + * :attr:`frequency0`, :attr:`frequency1`, :attr:`frequency2`: in units + of Hz :param channel_base: RTIO channel number of the first channel (amplitude). Frequency and Phase are then assumed to be successive channels. + :param parallelism: Number of output samples per coarse RTIO clock cycle. + :param core_device: Name of the core device that this SAWG is on. """ kernel_invariants = {"channel_base", "core", "amplitude1", "frequency1", "phase1", @@ -34,21 +39,21 @@ class SAWG: cordic_gain = 1.646760258057163 # Cordic(width=16, guard=None).gain # cfg: channel_base self.offset = Spline(width, time_width, channel_base + 1, - self.core, 1/2) + self.core, 2.) self.amplitude1 = Spline(width, time_width, channel_base + 2, - self.core, 1/(2*cordic_gain**2)) + self.core, 2*cordic_gain**2) self.frequency1 = Spline(3*width, time_width, channel_base + 3, - self.core, self.core.coarse_ref_period) + self.core, 1/self.core.coarse_ref_period) self.phase1 = Spline(width, time_width, channel_base + 4, self.core, 1.) self.amplitude2 = Spline(width, time_width, channel_base + 5, - self.core, 1/(2*cordic_gain**2)) + self.core, 2*cordic_gain**2) self.frequency2 = Spline(3*width, time_width, channel_base + 6, - self.core, self.core.coarse_ref_period) + self.core, 1/self.core.coarse_ref_period) self.phase2 = Spline(width, time_width, channel_base + 7, self.core, 1.) self.frequency0 = Spline(2*width, time_width, channel_base + 8, self.core, - self.core.coarse_ref_period/parallelism) + parallelism/self.core.coarse_ref_period) self.phase0 = Spline(width, time_width, channel_base + 9, self.core, 1.) diff --git a/artiq/coredevice/spline.py b/artiq/coredevice/spline.py index a6c99ddd9..2f75879d6 100644 --- a/artiq/coredevice/spline.py +++ b/artiq/coredevice/spline.py @@ -5,7 +5,7 @@ from artiq.language.types import TInt32, TInt64, TFloat class Spline: - """Spline interpolating RTIO channel. + r"""Spline interpolating RTIO channel. One knot of a polynomial basis spline (B-spline) :math:`u(t)` is defined by the coefficients :math:`u_n` up to order :math:`n = k`. @@ -13,8 +13,15 @@ class Spline: :math:`u(t)` for :math:`t > t_0, t_0` is: .. math:: - u(t) = \sum_{n=0}^k \frac{u_n}{n!} (t - t_0)^n - = u_0 + u_1 (t - t_0) + \frac{u_2}{2} (t - t_0)^2 + \dots + u(t) &= \sum_{n=0}^k \frac{u_n}{n!} (t - t_0)^n \\ + &= u_0 + u_1 (t - t_0) + \frac{u_2}{2} (t - t_0)^2 + \dots + + :param width: Width in bits of the quantity that this spline controls + :param time_width: Width in bits of the time counter of this spline + :param channel: RTIO channel number + :param core_device: Core device that this spline is attached to + :param scale: Scale for conversion between machine units and physical + units; to be given as the "full scale physical value". """ kernel_invariants = {"channel", "core", "scale", "width", @@ -24,7 +31,7 @@ class Spline: self.core = core_device self.channel = channel self.width = width - self.scale = float((int64(1) << width) * scale) + self.scale = float((int64(1) << width) / scale) self.time_width = time_width self.time_scale = float((1 << time_width) * core_device.coarse_ref_period) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index f6065de25..fdd467879 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -10,7 +10,7 @@ These drivers are for the core device and the peripherals closely integrated int :members: :mod:`artiq.coredevice.ttl` module ------------------------------------ +---------------------------------- .. automodule:: artiq.coredevice.ttl :members: @@ -43,7 +43,7 @@ These drivers are for the core device and the peripherals closely integrated int :members: :mod:`artiq.coredevice.cache` module ------------------------------------------ +------------------------------------ .. automodule:: artiq.coredevice.cache :members: @@ -54,6 +54,12 @@ These drivers are for the core device and the peripherals closely integrated int .. automodule:: artiq.coredevice.exceptions :members: +:mod:`artiq.coredevice.spline` module +------------------------------------- + +.. automodule:: artiq.coredevice.spline + :members: + :mod:`artiq.coredevice.sawg` module ----------------------------------- @@ -61,7 +67,7 @@ These drivers are for the core device and the peripherals closely integrated int :members: :mod:`artiq.coredevice.ad9154` module ------------------------------------ +------------------------------------- .. automodule:: artiq.coredevice.ad9154 :members: From d34084be0f3715948d9c87551831f4d23ce3b140 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 6 Dec 2016 20:22:47 +0100 Subject: [PATCH 146/157] README_PHASER: update --- README_PHASER.rst | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/README_PHASER.rst b/README_PHASER.rst index 5d4a3c7e4..aa0b5f187 100644 --- a/README_PHASER.rst +++ b/README_PHASER.rst @@ -1,16 +1,15 @@ ARTIQ Phaser ============ -This ARTIQ branch contains a proof-of-concept design of a GHz-datarate multichannel direct digital synthesizer (DDS) compatible with ARTIQ's RTIO channels. -In later developments this proof-of-concept can be expanded to provide a two-tone output with spline modulation and multi-DAC synchronization. -Ultimately it will be the basis for the ARTIQ Sayma Smart Arbitrary Waveform Generator project. See https://github.com/m-labs/sayma and https://github.com/m-labs/artiq-hardware. +This ARTIQ branch contains a proof-of-concept design of a GHz-datarate, multi-channel, interpolating, multi-tone, direct digital synthesizer (DDS) compatible with ARTIQ's RTIO channels. +Ultimately it will be the basis for the ARTIQ Sayma Smart Arbitrary Waveform Generator project. See https://github.com/m-labs/sinara and https://github.com/m-labs/artiq-hardware. *Features*: * up to 4 channels * up to 500 MHz data rate per channel (KC705 limitation) * up to 8x interpolation to 2.4 GHz DAC sample rate -* Real-time control over amplitude, frequency, phase of each channel through ARTIQ RTIO commands +* Real-time sample-coherent control over amplitude, frequency, phase of each channel through ARTIQ RTIO commands * Full configurability of the AD9154 and AD9516 through SPI with ARTIQ kernel support * All SPI registers and register bits exposed as human readable names * Parametrized JESD204B core (also capable of operation with eight lanes) @@ -18,12 +17,11 @@ Ultimately it will be the basis for the ARTIQ Sayma Smart Arbitrary Waveform Gen The hardware required to use the ARTIQ phaser branch is a KC705 with an AD9154-FMC-EBZ plugged into the HPC connector and a low-noise sample rate reference clock. -This work was supported by the Army Research Lab. +This work was supported by the Army Research Lab and the University of Maryland. The code that was developed for this project is located in several repositories: -* In ARTIQ, the SAWG and Phaser code: https://github.com/m-labs/artiq/compare/phaser -* The CORDIC core has been reused from the PDQ2 gateware https://github.com/m-labs/pdq2 +* In ARTIQ, the SAWG and Phaser code: https://github.com/m-labs/artiq/compare/phaser2 * The Migen/MiSoC JESD204B core: https://github.com/m-labs/jesd204b @@ -32,7 +30,7 @@ Installation These installation instructions are a short form of those in the ARTIQ manual. Please refer to and follow the ARTIQ manual for more details: -https://m-labs.hk/artiq/manual-release-2/index.html +https://m-labs.hk/artiq/manual-master/index.html * Set up a new conda environment and activate it. * Install the standard ARTIQ runtime/install dependencies. @@ -42,22 +40,20 @@ https://m-labs.hk/artiq/manual-release-2/index.html * Install the standard ARTIQ build dependencies. They are all available as conda packages in m-labs/main or m-labs/dev for linux-64: - - migen =0.4 - - misoc =0.4 - - llvm-or1k =3.8 + - migen + - misoc + - jesd204b + - llvm-or1k - rust-core-or1k - cargo - - binutils-or1k-linux >=2.27 + - binutils-or1k-linux * Install a recent version of Vivado (tested and developed with 2016.2). -* Checkout the ARTIQ phaser branch and the JESD204B core: :: +* Do a checkout of the ARTIQ phaser2 branch: :: mkdir ~/src cd ~/src - git clone --recursive -b phaser https://github.com/m-labs/artiq.git - git clone https://github.com/m-labs/jesd204b.git - cd jesd204b - python setup.py develop + git clone --recursive -b phaser2 https://github.com/m-labs/artiq.git cd ../artiq python setup.py develop @@ -74,11 +70,13 @@ Setup * Compile the ARTIQ Phaser bitstream, bios, and runtime (c.f. ARTIQ manual): :: - python -m artiq.gateware.targets.phaser --toolchain vivado + python -m artiq.gateware.targets.phaser +* Generate an ARTIQ configuration flash image with MAC and IP address (see the + documentation for ``artiq_mkfs``). Name it ``phaser_config.bin``. * Run the following OpenOCD command to flash the ARTIQ phaser design: :: - openocd -f board/kc705.cfg -c "init; jtagspi_init 0 bscan_spi_xc7k325t.bit; jtagspi_program misoc_phaser_kc705/gateware/top.bin 0x000000; jtagspi_program misoc_phaser_kc705/software/bios/bios.bin 0xaf0000; jtagspi_program misoc_phaser_kc705/software/runtime/runtime.fbi 0xb00000; xc7_program xc7.tap; exit" + openocd -f board/kc705.cfg -c "init; jtagspi_init 0 bscan_spi_xc7k325t.bit; jtagspi_program misoc_phaser_kc705/gateware/top.bin 0x000000; jtagspi_program misoc_phaser_kc705/software/bios/bios.bin 0xaf0000; jtagspi_program misoc_phaser_kc705/software/runtime/runtime.fbi 0xb00000;jtagspi_program phaser_config.bin 0xb80000; xc7_program xc7.tap; exit" The proxy bitstream ``bscan_spi_xc7k325t.bit`` can be found at https://github.com/jordens/bscan_spi_bitstreams or in any ARTIQ conda package for the KC705. See the source code of ``artiq_flash.py`` from ARTIQ for more details. @@ -91,7 +89,7 @@ Setup * Refer to the ARTIQ documentation to configure an IP address and other settings for the transmitter device. If the board was running stock ARTIQ before, the settings will be kept. * A 300 MHz clock of roughly 10 dBm (0.2 to 3.4 V peak-to-peak into 50 Ohm) must be connected to the AD9154-FMC-EBZ J1. - The external RTIO clock, DAC deviceclock, FPGA deviceclock, and SYSREF are derived from this signal. + The external RTIO clock, DAC deviceclock, FPGA deviceclock, and SYSREF are derived from this signal. There is no internal RTIO clock. * An example device database, several status and test scripts are provided in ``artiq/examples/phaser/``. :: cd artiq/examples/phaser @@ -109,9 +107,9 @@ Usage * Run ``artiq_run repository/ad9154_test_status.py`` to retrieve and print several status registers from the AD9154 DAC. * Run ``artiq_run repository/ad9154_test_prbs.py`` to test the JESD204B PHY layer for bit errors. Reboot the core device afterwards. * Run ``artiq_run repository/ad9154_test_stpl.py`` to executes a JESD204B short transport layer test. -* Run ``artiq_run repository/sawg.py`` for an example that sets up amplitudes, frequencies, and phases on all four DDS channels. * Run ``artiq_run repository/demo.py`` for an example that exercises several different use cases of synchronized phase, amplitude, and frequency updates. for an example that exercises several different use cases of synchronized phase, amplitude, and frequency updates. +* Run ``artiq_run repository/demo_2tone.py`` for an example that emits a shaped two-tone pulse. * Implement your own experiments using the SAWG channels. * Verify clock stability between the sample rate reference clock and the DAC outputs. * Changes to the AD9154 configuration can also be performed at runtime in experiments. From 7e0f3edca55b5fe912c132243276f5f6374c193b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 7 Dec 2016 19:14:23 +0100 Subject: [PATCH 147/157] gateware/dsp: add FIR and test --- artiq/gateware/dsp/fir.py | 68 ++++++++++++++++++++++++++++ artiq/test/gateware/test_fir.py | 78 +++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 artiq/gateware/dsp/fir.py create mode 100644 artiq/test/gateware/test_fir.py diff --git a/artiq/gateware/dsp/fir.py b/artiq/gateware/dsp/fir.py new file mode 100644 index 000000000..50628864f --- /dev/null +++ b/artiq/gateware/dsp/fir.py @@ -0,0 +1,68 @@ +from operator import add +from functools import reduce +import numpy as np +from migen import * + + +def halfgen4(up, n): + """ + http://recycle.lbl.gov/~ldoolitt/halfband + + params: + * `up` is the stopband width, as a fraction of input sampling rate + * `n is the order of half-band filter to generate + returns: + * `a` is the full set of FIR coefficients, `4*n-1` long. + implement wisely. + """ + + npt = n*40 + wmax = 2*np.pi*up + wfit = (1 - np.linspace(0, 1, npt)[:, None]**2)*wmax + + target = .5*np.ones_like(wfit) + basis = np.cos(wfit*np.arange(1, 2*n, 2)) + l = np.linalg.pinv(basis)@target + + weight = np.ones_like(wfit) + for i in range(40): + err = np.fabs(basis@l - .5) + weight[err > .99*np.max(err)] *= 1 + 1.5/(i + 11) + l = np.linalg.pinv(basis*weight)@(target*weight) + a = np.c_[l, np.zeros_like(l)].ravel()[:-1] + a = np.r_[a[::-1], 1, a]/2 + return a + + +class FIR(Module): + """Full-rate finite impulse response filter. + + :param coefficients: integer taps. + :param width: bit width of input and output. + :param shift: scale factor (as power of two). + """ + def __init__(self, coefficients, width=16, shift=None): + self.width = width + self.i = Signal((width, True)) + self.o = Signal((width, True)) + self.latency = (len(coefficients) + 1)//2 + 1 + + ### + + n = len(coefficients) + x = [Signal((width, True)) for _ in range(n)] + self.comb += x[0].eq(self.i) + self.sync += [x[i + 1].eq(x[i]) for i in range(n - 1)] + + o = [] + for i, c in enumerate(coefficients): + # simplify for halfband and symmetric filters + if c == 0 or c in coefficients[:i]: + continue + o.append(c*reduce(add, [ + xj for xj, cj in zip(x, coefficients) if cj == c + ])) + + if shift is None: + shift = width - 1 + self.sync += self.o.eq(reduce(add, o) >> shift) diff --git a/artiq/test/gateware/test_fir.py b/artiq/test/gateware/test_fir.py new file mode 100644 index 000000000..55181f7e9 --- /dev/null +++ b/artiq/test/gateware/test_fir.py @@ -0,0 +1,78 @@ +import numpy as np +import matplotlib.pyplot as plt + +from migen import * +from migen.fhdl import verilog +from artiq.gateware.dsp import fir + + +class Transfer(Module): + def __init__(self, dut): + self.submodules.dut = dut + + def drive(self, x): + for xi in x: + yield self.dut.i.eq(int(xi)) + yield + + def record(self, y): + for i in range(self.dut.latency): + yield + for i in range(len(y)): + y[i] = (yield self.dut.o) + yield + + def run(self, samples, amplitude=1.): + w = 2**(self.dut.width - 1) - 1 + x = np.round(np.random.uniform( + -amplitude*w, amplitude*w, samples)) + y = np.empty_like(x) + run_simulation(self, [self.drive(x), self.record(y)], + vcd_name="fir.vcd") + x /= w + y /= w + return x, y + + def analyze(self, x, y): + fig, ax = plt.subplots(3) + ax[0].plot(x, "c-.", label="input") + ax[0].plot(y, "r-", label="output") + ax[0].legend(loc="right") + ax[0].set_xlabel("time (1/fs)") + ax[0].set_ylabel("signal") + n = len(x) + w = np.hanning(n) + x = (x.reshape(-1, n)*w).sum(0) + y = (y.reshape(-1, n)*w).sum(0) + t = (np.fft.rfft(y)/np.fft.rfft(x)) + f = np.fft.rfftfreq(n)*2 + fmin = f[1] + ax[1].plot(f, 20*np.log10(np.abs(t)), "r-") + ax[1].set_ylim(-70, 3) + ax[1].set_xlim(fmin, 1.) + # ax[1].set_xscale("log") + ax[1].set_xlabel("frequency (fs/2)") + ax[1].set_ylabel("magnitude (dB)") + ax[1].grid(True) + ax[2].plot(f, np.rad2deg(np.angle(t)), "r-") + ax[2].set_xlim(fmin, 1.) + # ax[2].set_xscale("log") + ax[2].set_xlabel("frequency (fs/2)") + ax[2].set_ylabel("phase (deg)") + ax[2].grid(True) + return fig + + +def _main(): + coeff = fir.halfgen4(.4/2, 8) + coeff_int = [int(round(c * (1 << 16 - 1))) for c in coeff] + dut = fir.FIR(coeff_int, width=16) + # print(verilog.convert(dut, ios={dut.i, dut.o})) + tb = Transfer(dut) + x, y = tb.run(samples=1 << 10, amplitude=.8) + tb.analyze(x, y) + plt.show() + + +if __name__ == "__main__": + _main() From d303225249de9ebd41b2a73790d95c040b64fe2c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 8 Dec 2016 13:05:13 +0100 Subject: [PATCH 148/157] fir: add ParallelFIR and test --- artiq/gateware/dsp/fir.py | 52 +++++++++++++++++++++++++++++---- artiq/test/gateware/test_fir.py | 27 ++++++++++++++--- 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/dsp/fir.py b/artiq/gateware/dsp/fir.py index 50628864f..09f6bd58a 100644 --- a/artiq/gateware/dsp/fir.py +++ b/artiq/gateware/dsp/fir.py @@ -45,24 +45,64 @@ class FIR(Module): self.width = width self.i = Signal((width, True)) self.o = Signal((width, True)) - self.latency = (len(coefficients) + 1)//2 + 1 + n = len(coefficients) + self.latency = (n + 1)//2 + 1 ### - n = len(coefficients) + # Delay line: increasing delay x = [Signal((width, True)) for _ in range(n)] - self.comb += x[0].eq(self.i) - self.sync += [x[i + 1].eq(x[i]) for i in range(n - 1)] + self.sync += [xi.eq(xj) for xi, xj in zip(x, [self.i] + x)] + # Wire up output o = [] for i, c in enumerate(coefficients): # simplify for halfband and symmetric filters - if c == 0 or c in coefficients[:i]: + if c == 0 or c in coefficients[i + 1:]: continue o.append(c*reduce(add, [ - xj for xj, cj in zip(x, coefficients) if cj == c + xj for xj, cj in zip(x[::-1], coefficients) if cj == c ])) if shift is None: shift = width - 1 self.sync += self.o.eq(reduce(add, o) >> shift) + + +class ParallelFIR(Module): + """Full-rate parallelized finite impulse response filter. + + :param coefficients: integer taps. + :param parallelism: number of samples per cycle. + :param width: bit width of input and output. + :param shift: scale factor (as power of two). + """ + def __init__(self, coefficients, parallelism, width=16, shift=None): + self.width = width + self.parallelism = p = parallelism + n = len(coefficients) + # input and output: old to young, decreasing delay + self.i = [Signal((width, True)) for i in range(p)] + self.o = [Signal((width, True)) for i in range(p)] + self.latency = (n + 1)//2//parallelism + 2 # minus .5 + + ### + + # Delay line: young to old, increasing delay + x = [Signal((width, True)) for _ in range(n + p - 1)] + self.sync += [xi.eq(xj) for xi, xj in zip(x, self.i[::-1] + x)] + + if shift is None: + shift = width - 1 + + # wire up each output + for j in range(p): + o = [] + for i, c in enumerate(coefficients): + # simplify for halfband and symmetric filters + if c == 0 or c in coefficients[i + 1:]: + continue + o.append(c*reduce(add, [ + xj for xj, cj in zip(x[-1 - j::-1], coefficients) if cj == c + ])) + self.sync += self.o[j].eq(reduce(add, o) >> shift) diff --git a/artiq/test/gateware/test_fir.py b/artiq/test/gateware/test_fir.py index 55181f7e9..1588b1636 100644 --- a/artiq/test/gateware/test_fir.py +++ b/artiq/test/gateware/test_fir.py @@ -19,8 +19,8 @@ class Transfer(Module): for i in range(self.dut.latency): yield for i in range(len(y)): - y[i] = (yield self.dut.o) yield + y[i] = (yield self.dut.o) def run(self, samples, amplitude=1.): w = 2**(self.dut.width - 1) - 1 @@ -63,12 +63,31 @@ class Transfer(Module): return fig +class ParallelTransfer(Transfer): + def drive(self, x): + for xi in x.reshape(-1, self.dut.parallelism): + yield [ij.eq(int(xj)) for ij, xj in zip(self.dut.i, xi)] + yield + + def record(self, y): + for i in range(self.dut.latency): + yield + for yi in y.reshape(-1, self.dut.parallelism): + yield + yi[:] = (yield from [(yield o) for o in self.dut.o]) + + def _main(): coeff = fir.halfgen4(.4/2, 8) coeff_int = [int(round(c * (1 << 16 - 1))) for c in coeff] - dut = fir.FIR(coeff_int, width=16) - # print(verilog.convert(dut, ios={dut.i, dut.o})) - tb = Transfer(dut) + if False: + dut = fir.FIR(coeff_int, width=16) + # print(verilog.convert(dut, ios={dut.i, dut.o})) + tb = Transfer(dut) + else: + dut = fir.ParallelFIR(coeff_int, parallelism=4, width=16) + # print(verilog.convert(dut, ios=set(dut.i + dut.o))) + tb = ParallelTransfer(dut) x, y = tb.run(samples=1 << 10, amplitude=.8) tb.analyze(x, y) plt.show() From a629eb16658c9f1636540c8aaebcf9bf54945af5 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 8 Dec 2016 15:30:26 +0100 Subject: [PATCH 149/157] fir: add ParallelHBFCascade --- artiq/gateware/dsp/fir.py | 48 ++++++++++++++++++++++++++++++--- artiq/test/gateware/test_fir.py | 14 +++++++--- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/dsp/fir.py b/artiq/gateware/dsp/fir.py index 09f6bd58a..7893c04bf 100644 --- a/artiq/gateware/dsp/fir.py +++ b/artiq/gateware/dsp/fir.py @@ -4,12 +4,13 @@ import numpy as np from migen import * -def halfgen4(up, n): +def halfgen4(width, n): """ http://recycle.lbl.gov/~ldoolitt/halfband params: - * `up` is the stopband width, as a fraction of input sampling rate + * `up` is the passband/stopband width, as a fraction of + input sampling rate * `n is the order of half-band filter to generate returns: * `a` is the full set of FIR coefficients, `4*n-1` long. @@ -17,7 +18,7 @@ def halfgen4(up, n): """ npt = n*40 - wmax = 2*np.pi*up + wmax = 2*np.pi*width wfit = (1 - np.linspace(0, 1, npt)[:, None]**2)*wmax target = .5*np.ones_like(wfit) @@ -106,3 +107,44 @@ class ParallelFIR(Module): xj for xj, cj in zip(x[-1 - j::-1], coefficients) if cj == c ])) self.sync += self.o[j].eq(reduce(add, o) >> shift) + + +def halfgen4_cascade(rate, width, order=None): + """Generate coefficients for cascaded half-band filters. + + :param rate: upsampling rate. power of two + :param width: passband/stopband width in units of input sampling rate. + :param order: highest order, defaults to :param:`rate`""" + if order is None: + order = rate + coeff = [] + p = 1 + while p < rate: + p *= 2 + coeff.append(halfgen4(width*p/rate/2, order*p//rate)) + return coeff + + +class ParallelHBFUpsampler(Module): + """Parallel, power-of-two, half-band, cascading upsampler. + + Coefficients should be normalized to overall gain of 2 + (highest/center coefficient being 1).""" + def __init__(self, coefficients, width=16, **kwargs): + self.parallelism = 1 + self.latency = 0 + self.width = width + self.i = Signal((width, True)) + + ### + + i = [self.i] + for coeff in coefficients: + self.parallelism *= 2 + # assert coeff[len(coeff)//2 + 1] == 1 + hbf = ParallelFIR(coeff, self.parallelism, width, **kwargs) + self.submodules += hbf + self.comb += [a.eq(b) for a, b in zip(hbf.i[::2], i)] + i = hbf.o + self.latency += hbf.latency + self.o = i diff --git a/artiq/test/gateware/test_fir.py b/artiq/test/gateware/test_fir.py index 1588b1636..f26047d0b 100644 --- a/artiq/test/gateware/test_fir.py +++ b/artiq/test/gateware/test_fir.py @@ -81,13 +81,19 @@ def _main(): coeff = fir.halfgen4(.4/2, 8) coeff_int = [int(round(c * (1 << 16 - 1))) for c in coeff] if False: - dut = fir.FIR(coeff_int, width=16) - # print(verilog.convert(dut, ios={dut.i, dut.o})) - tb = Transfer(dut) - else: + coeff = [[int(round((1 << 26) * ci)) for ci in c] + for c in fir.halfgen4_cascade(8, width=.4, order=8)] + dut = fir.ParallelHBFUpsampler(coeff, width=16, shift=25) + print(verilog.convert(dut, ios=set([dut.i] + dut.o))) + elif True: dut = fir.ParallelFIR(coeff_int, parallelism=4, width=16) # print(verilog.convert(dut, ios=set(dut.i + dut.o))) tb = ParallelTransfer(dut) + else: + dut = fir.FIR(coeff_int, width=16) + # print(verilog.convert(dut, ios={dut.i, dut.o})) + tb = Transfer(dut) + x, y = tb.run(samples=1 << 10, amplitude=.8) tb.analyze(x, y) plt.show() From 3eef6229cca86f16a8717d0e32580f1c4cdbcff6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 8 Dec 2016 15:32:57 +0100 Subject: [PATCH 150/157] sawg: use ParallelHBFCascade to AA [WIP] --- artiq/gateware/dsp/sawg.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 4f13f87c1..0b97f37ea 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -4,9 +4,10 @@ from migen import * from misoc.interconnect.stream import Endpoint from misoc.cores.cordic import Cordic -from .accu import PhasedAccu, Accu +from .accu import PhasedAccu from .tools import eqh, Delay, SatAddMixin from .spline import Spline +from .fir import ParallelHBFUpsampler, halfgen4_cascade _Widths = namedtuple("_Widths", "t a p f") @@ -145,13 +146,17 @@ class Channel(Module, SatAddMixin): self.submodules.a1 = a1 = SplineParallelDDS(widths, orders) self.submodules.a2 = a2 = SplineParallelDDS(widths, orders) + coeff = [[int(round((1 << 26) * ci)) for ci in c] + for c in halfgen4_cascade(parallelism, width=.4, order=8)] + hbf = [ParallelHBFUpsampler(coeff, width=width, shift=25) + for i in range(2)] self.submodules.b = b = SplineParallelDUC( widths._replace(a=len(a1.xo[0]), f=widths.f - width), orders, - parallelism=parallelism, a_delay=-a1.latency) + parallelism=parallelism, a_delay=-a1.latency-hbf[0].latency) cfg = Config(widths.a) u = Spline(width=widths.a, order=orders.a) - du = Delay(width, a1.latency + b.latency - u.latency) - self.submodules += cfg, u, du + du = Delay(width, a1.latency + hbf[0].latency + b.latency - u.latency) + self.submodules += cfg, u, du, hbf self.u = u.tri(widths.t) self.i = [cfg.i, self.u, a1.a, a1.f, a1.p, a2.a, a2.f, a2.p, b.f, b.p] self.i_names = "cfg u a1 f1 p1 a2 f2 p2 f0 p0".split() @@ -174,12 +179,14 @@ class Channel(Module, SatAddMixin): Cat(a1.clr, a2.clr, b.clr).eq(cfg.clr), ] self.sync += [ - b.i.x.eq(self.sat_add(a1.xo[0], a2.xo[0], - limits=cfg.limits[0], - clipped=cfg.clipped[0])), - b.i.y.eq(self.sat_add(a1.yo[0], a2.yo[0], - limits=cfg.limits[1], - clipped=cfg.clipped[1])), + hbf[0].i.eq(self.sat_add(a1.xo[0], a2.xo[0], + limits=cfg.limits[0], + clipped=cfg.clipped[0])), + hbf[1].i.eq(self.sat_add(a1.yo[0], a2.yo[0], + limits=cfg.limits[1], + clipped=cfg.clipped[1])), + b.i.x.eq(hbf[0].o[0]), # FIXME: rip up + b.i.y.eq(hbf[1].o[0]), eqh(du.i, u.o.a0), ] # wire up outputs and q_{i,o} exchange From efc95043c4cef825104c0ad70b57379e80ef706a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 8 Dec 2016 15:49:23 +0100 Subject: [PATCH 151/157] test/sawg: patch spline --- artiq/test/gateware/test_sawg_fe.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/test/gateware/test_sawg_fe.py b/artiq/test/gateware/test_sawg_fe.py index c7272f267..34a850c62 100644 --- a/artiq/test/gateware/test_sawg_fe.py +++ b/artiq/test/gateware/test_sawg_fe.py @@ -3,7 +3,7 @@ import unittest import migen as mg from numpy import int32 -from artiq.coredevice import sawg +from artiq.coredevice import sawg, spline from artiq.language import (at_mu, now_mu, delay, core as core_language) from artiq.gateware.rtio.phy.sawg import Channel @@ -36,7 +36,7 @@ class SAWGTest(unittest.TestCase): def setUp(self): core_language.set_time_manager(sim_time.Manager()) self.rtio_manager = RTIOManager() - self.rtio_manager.patch(sawg) + self.rtio_manager.patch(spline) self.core = sim_devices.Core({}) self.core.coarse_ref_period = 6.66666 self.t = self.core.coarse_ref_period @@ -46,7 +46,7 @@ class SAWGTest(unittest.TestCase): parallelism=self.channel.parallelism) def tearDown(self): - self.rtio_manager.unpatch(sawg) + self.rtio_manager.unpatch(spline) def test_instantiate(self): pass From f4ceace2537782072ddcfcfde2ec2b02a3f8b8af Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 8 Dec 2016 15:49:50 +0100 Subject: [PATCH 152/157] test/fir: needs mpl. don't run by default --- artiq/test/gateware/{test_fir.py => fir.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename artiq/test/gateware/{test_fir.py => fir.py} (100%) diff --git a/artiq/test/gateware/test_fir.py b/artiq/test/gateware/fir.py similarity index 100% rename from artiq/test/gateware/test_fir.py rename to artiq/test/gateware/fir.py From 598da09a93a02c5f8f5a911bccb3dd8dc751a0d2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 8 Dec 2016 15:51:01 +0100 Subject: [PATCH 153/157] sawg: fix latency --- artiq/gateware/dsp/sawg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 0b97f37ea..4001eb09d 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -166,7 +166,7 @@ class Channel(Module, SatAddMixin): self.widths = widths self.orders = orders self.parallelism = parallelism - self.latency = a1.latency + b.latency + 2 + self.latency = a1.latency + hbf[0].latency + b.latency + 2 self.cordic_gain = a1.gain*b.gain ### From 18e3f58c22e5c1b5a8e1c9577b4f587637052e70 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 8 Dec 2016 16:14:32 +0100 Subject: [PATCH 154/157] sawg: reduce coefficient width --- artiq/gateware/dsp/sawg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 4001eb09d..fb4d45eac 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -146,9 +146,9 @@ class Channel(Module, SatAddMixin): self.submodules.a1 = a1 = SplineParallelDDS(widths, orders) self.submodules.a2 = a2 = SplineParallelDDS(widths, orders) - coeff = [[int(round((1 << 26) * ci)) for ci in c] + coeff = [[int(round((1 << 18)*ci)) for ci in c] for c in halfgen4_cascade(parallelism, width=.4, order=8)] - hbf = [ParallelHBFUpsampler(coeff, width=width, shift=25) + hbf = [ParallelHBFUpsampler(coeff, width=width, shift=17) for i in range(2)] self.submodules.b = b = SplineParallelDUC( widths._replace(a=len(a1.xo[0]), f=widths.f - width), orders, From ca636ef28a6b76a64ab6cb929daee33dc43a3bc0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 8 Dec 2016 16:23:40 +0100 Subject: [PATCH 155/157] conda/phaser: build-depend on numpy --- conda/artiq-kc705-phaser/meta.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/conda/artiq-kc705-phaser/meta.yaml b/conda/artiq-kc705-phaser/meta.yaml index bb6c61096..e843ec666 100644 --- a/conda/artiq-kc705-phaser/meta.yaml +++ b/conda/artiq-kc705-phaser/meta.yaml @@ -19,6 +19,7 @@ requirements: - binutils-or1k-linux >=2.27 - rust-core-or1k - cargo + - numpy run: - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_DESCRIBE_HASH")[1:]) if "GIT_DESCRIBE_TAG" in environ else "" }} From b7a308d33d982cd25c92cf71c7469f3a9ef70f59 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 8 Dec 2016 17:00:39 +0100 Subject: [PATCH 156/157] fir: register multiplier output --- artiq/gateware/dsp/fir.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/dsp/fir.py b/artiq/gateware/dsp/fir.py index 7893c04bf..6f1535528 100644 --- a/artiq/gateware/dsp/fir.py +++ b/artiq/gateware/dsp/fir.py @@ -47,7 +47,7 @@ class FIR(Module): self.i = Signal((width, True)) self.o = Signal((width, True)) n = len(coefficients) - self.latency = (n + 1)//2 + 1 + self.latency = (n + 1)//2 + 2 ### @@ -55,18 +55,22 @@ class FIR(Module): x = [Signal((width, True)) for _ in range(n)] self.sync += [xi.eq(xj) for xi, xj in zip(x, [self.i] + x)] - # Wire up output + if shift is None: + shift = width - 1 + + # Make products o = [] for i, c in enumerate(coefficients): # simplify for halfband and symmetric filters if c == 0 or c in coefficients[i + 1:]: continue - o.append(c*reduce(add, [ + m = Signal((width + shift, True)) + self.sync += m.eq(c*reduce(add, [ xj for xj, cj in zip(x[::-1], coefficients) if cj == c ])) + o.append(m) - if shift is None: - shift = width - 1 + # Make sum self.sync += self.o.eq(reduce(add, o) >> shift) @@ -85,7 +89,7 @@ class ParallelFIR(Module): # input and output: old to young, decreasing delay self.i = [Signal((width, True)) for i in range(p)] self.o = [Signal((width, True)) for i in range(p)] - self.latency = (n + 1)//2//parallelism + 2 # minus .5 + self.latency = (n + 1)//2//parallelism + 3 # minus one sample ### @@ -96,16 +100,19 @@ class ParallelFIR(Module): if shift is None: shift = width - 1 - # wire up each output for j in range(p): + # Make products o = [] for i, c in enumerate(coefficients): # simplify for halfband and symmetric filters if c == 0 or c in coefficients[i + 1:]: continue - o.append(c*reduce(add, [ + m = Signal((width + shift, True)) + self.sync += m.eq(c*reduce(add, [ xj for xj, cj in zip(x[-1 - j::-1], coefficients) if cj == c ])) + o.append(m) + # Make sum self.sync += self.o[j].eq(reduce(add, o) >> shift) From f6071a58125a0fdbf5fc55dd9b38dc0c61bc7740 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 8 Dec 2016 17:00:53 +0100 Subject: [PATCH 157/157] sawg/hbf: tweak pipeline for timing --- artiq/gateware/dsp/sawg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index fb4d45eac..080d73fbb 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -177,6 +177,8 @@ class Channel(Module, SatAddMixin): b.ce.eq(cfg.ce), u.o.ack.eq(cfg.ce), Cat(a1.clr, a2.clr, b.clr).eq(cfg.clr), + b.i.x.eq(hbf[0].o[0]), # FIXME: rip up + b.i.y.eq(hbf[1].o[0]), ] self.sync += [ hbf[0].i.eq(self.sat_add(a1.xo[0], a2.xo[0], @@ -185,8 +187,6 @@ class Channel(Module, SatAddMixin): hbf[1].i.eq(self.sat_add(a1.yo[0], a2.yo[0], limits=cfg.limits[1], clipped=cfg.clipped[1])), - b.i.x.eq(hbf[0].o[0]), # FIXME: rip up - b.i.y.eq(hbf[1].o[0]), eqh(du.i, u.o.a0), ] # wire up outputs and q_{i,o} exchange