forked from M-Labs/artiq
1
0
Fork 0

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
This commit is contained in:
Robert Jördens 2016-07-22 15:56:09 +02:00
parent 2bc5dc4ecb
commit 4a0eaf0f95
32 changed files with 5155 additions and 6 deletions

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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

73
artiq/coredevice/sawg.py Normal file
View File

@ -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))

View File

@ -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}
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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))

View File

@ -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))

View File

@ -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))

View File

112
artiq/gateware/dsp/accu.py Normal file
View File

@ -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),
),
]

View File

@ -0,0 +1,358 @@
# Copyright 2014-2015 Robert Jordens <jordens@gmail.com>
#
# 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 <http://www.gnu.org/licenses/>.
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))
)
]

View File

@ -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

View File

@ -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

71
artiq/gateware/phaser.py Normal file
View File

@ -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"))
),
]

View File

@ -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))

View File

@ -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)")

View File

@ -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 \

57
artiq/runtime/ad9154.c Normal file
View File

@ -0,0 +1,57 @@
#include <generated/csr.h>
#include <stdint.h>
#include <stddef.h>
#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 */

14
artiq/runtime/ad9154.h Normal file
View File

@ -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

View File

@ -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}
};

View File

@ -34,6 +34,7 @@
#include "session.h"
#include "analyzer.h"
#include "moninj.h"
#include "ad9154.h"
u32_t sys_now(void)
{

View File

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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'

View File

@ -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
-----------

View File

@ -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:

View File

@ -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 <flash-mac-ip-addr>`.
.. _configuring-core-device:
Configuring the core device
---------------------------