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.vivado import XilinxVivadoToolchain
from migen.build.xilinx.ise import XilinxISEToolchain from migen.build.xilinx.ise import XilinxISEToolchain
from migen.fhdl.specials import Keep from migen.fhdl.specials import Keep
from migen.genlib.io import DifferentialInput
from misoc.interconnect.csr import * from misoc.interconnect.csr import *
from misoc.interconnect import wishbone from misoc.interconnect import wishbone
from misoc.cores import gpio from misoc.cores import gpio
from misoc.cores import spi as spi_csr
from misoc.integration.soc_core import mem_decoder from misoc.integration.soc_core import mem_decoder
from misoc.targets.kc705 import MiniSoC, soc_kc705_args, soc_kc705_argdict from misoc.targets.kc705 import MiniSoC, soc_kc705_args, soc_kc705_argdict
from misoc.integration.builder import builder_args, builder_argdict from misoc.integration.builder import builder_args, builder_argdict
from artiq.gateware.soc import AMPSoC, build_artiq_soc from artiq.gateware.soc import AMPSoC, build_artiq_soc
from artiq.gateware import rtio, nist_qc1, nist_clock, nist_qc2 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 from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series,
dds, spi, sawg)
from artiq import __version__ as artiq_version from artiq import __version__ as artiq_version
@ -138,8 +141,8 @@ class _NIST_Ions(MiniSoC, AMPSoC):
self.register_kernel_cpu_csrdevice("i2c") self.register_kernel_cpu_csrdevice("i2c")
self.config["I2C_BUS_COUNT"] = 1 self.config["I2C_BUS_COUNT"] = 1
def add_rtio(self, rtio_channels): def add_rtio(self, rtio_channels, crg=_RTIOCRG):
self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) self.submodules.rtio_crg = crg(self.platform, self.crg.cd_sys.clk)
self.csr_devices.append("rtio_crg") self.csr_devices.append("rtio_crg")
self.submodules.rtio = rtio.RTIO(rtio_channels) self.submodules.rtio = rtio.RTIO(rtio_channels)
self.register_kernel_cpu_csrdevice("rtio") 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 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(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="ARTIQ core device builder / KC705 " description="ARTIQ core device builder / KC705 "
@ -388,7 +520,7 @@ def main():
soc_kc705_args(parser) soc_kc705_args(parser)
parser.add_argument("-H", "--hw-adapter", default="nist_clock", parser.add_argument("-H", "--hw-adapter", default="nist_clock",
help="hardware adapter type: " help="hardware adapter type: "
"nist_qc1/nist_clock/nist_qc2 " "nist_qc1/nist_clock/nist_qc2/phaser "
"(default: %(default)s)") "(default: %(default)s)")
args = parser.parse_args() args = parser.parse_args()
@ -399,6 +531,8 @@ def main():
cls = NIST_CLOCK cls = NIST_CLOCK
elif hw_adapter == "nist_qc2": elif hw_adapter == "nist_qc2":
cls = NIST_QC2 cls = NIST_QC2
elif hw_adapter == "phaser":
cls = Phaser
else: else:
raise SystemExit("Invalid hardware adapter string (-H/--hw-adapter)") 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 \ session.o log.o analyzer.o moninj.o net_server.o bridge_ctl.o \
ksupport_data.o kloader.o test_mode.o main.o ksupport_data.o kloader.o test_mode.o main.o
OBJECTS_KSUPPORT := ksupport.o artiq_personality.o mailbox.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) \ CFLAGS += -I$(LIBALLOC_DIRECTORY) \
-I$(MISOC_DIRECTORY)/software/include/dyld \ -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 "rtio.h"
#include "dds.h" #include "dds.h"
#include "i2c.h" #include "i2c.h"
#include "ad9154.h"
double round(double x); double round(double x);
double sqrt(double x); double sqrt(double x);
@ -137,6 +138,14 @@ static const struct symbol runtime_exports[] = {
{"cache_get", &cache_get}, {"cache_get", &cache_get},
{"cache_put", &cache_put}, {"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 */ /* end */
{NULL, NULL} {NULL, NULL}
}; };

View File

@ -34,6 +34,7 @@
#include "session.h" #include "session.h"
#include "analyzer.h" #include "analyzer.h"
#include "moninj.h" #include "moninj.h"
#include "ad9154.h"
u32_t sys_now(void) 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. 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 Pipistrello
----------- -----------

View File

@ -53,3 +53,15 @@ These drivers are for the core device and the peripherals closely integrated int
.. automodule:: artiq.coredevice.exceptions .. automodule:: artiq.coredevice.exceptions
:members: :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>`. 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 Configuring the core device
--------------------------- ---------------------------