Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1b08e65fa1ff
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 6c899e6ba64f
Choose a head ref
  • 10 commits
  • 12 files changed
  • 1 contributor

Commits on Feb 29, 2016

  1. Copy the full SHA
    f73228f View commit details
  2. Revert "gateware/rt2wb: support combinatorial ack"

    This reverts commit f73228f.
    jordens committed Feb 29, 2016
    Copy the full SHA
    cb8815c View commit details
  3. Revert "gateware/rt2wb: only input when active"

    This reverts commit 1b08e65.
    jordens committed Feb 29, 2016
    Copy the full SHA
    a0083f4 View commit details
  4. Copy the full SHA
    dd57072 View commit details
  5. coredevice/spi: clean up api

    jordens committed Feb 29, 2016
    Copy the full SHA
    e113668 View commit details
  6. Copy the full SHA
    d3c9482 View commit details
  7. runtime: refactor rt2wb/dds

    jordens committed Feb 29, 2016
    Copy the full SHA
    5dae9f8 View commit details
  8. Copy the full SHA
    ecedbbe View commit details
  9. coredevice.spi: cleanup

    jordens committed Feb 29, 2016
    Copy the full SHA
    16537d3 View commit details
  10. 10
    Copy the full SHA
    6c899e6 View commit details
7 changes: 4 additions & 3 deletions artiq/coredevice/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from artiq.coredevice import exceptions, dds
from artiq.coredevice import exceptions, dds, spi
from artiq.coredevice.exceptions import (RTIOUnderflow, RTIOSequenceError,
RTIOCollisionError, RTIOOverflow,
DDSBatchError, CacheError)
DDSBatchError, CacheError,
RTIOTimeout)
from artiq.coredevice.dds import (PHASE_MODE_CONTINUOUS, PHASE_MODE_ABSOLUTE,
PHASE_MODE_TRACKING)

__all__ = []
__all__ += ["RTIOUnderflow", "RTIOSequenceError", "RTIOCollisionError",
"RTIOOverflow", "DDSBatchError", "CacheError"]
"RTIOOverflow", "DDSBatchError", "CacheError", "RTIOTimeout"]
__all__ += ["PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE",
"PHASE_MODE_TRACKING"]
11 changes: 11 additions & 0 deletions artiq/coredevice/exceptions.py
Original file line number Diff line number Diff line change
@@ -108,6 +108,17 @@ class RTIOOverflow(Exception):
"""
artiq_builtin = True

class RTIOTimeout(Exception):
"""Raised when an RTIO input operation does not complete within the expected
time. This is only raised by channels where a response is guaranteed, such
as RT2WB (DDS and SPI).
This does not interrupt operations further than cancelling the current read
attempt. Reading can be reattempted after the exception is caught, and
events that have arrived in the meantime will be retrieved.
"""
artiq_builtin = True

class DDSBatchError(Exception):
"""Raised when attempting to start a DDS batch while already in a batch,
or when too many commands are batched.
89 changes: 51 additions & 38 deletions artiq/coredevice/spi.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from artiq.language.core import *
from artiq.language.types import *
from artiq.coredevice.rt2wb import *
from artiq.language.core import (kernel, portable, seconds_to_mu, now_mu,
delay_mu)
from artiq.language.units import MHz
from artiq.coredevice.rt2wb import rt2wb_write, rt2wb_read_sync


SPI_DATA_ADDR, SPI_XFER_ADDR, SPI_CONFIG_ADDR = range(3)
@@ -26,56 +27,68 @@ class SPIMaster:
"""
def __init__(self, dmgr, ref_period, channel):
self.core = dmgr.get("core")
self.ref_period = ref_period
self.ref_period_mu = seconds_to_mu(ref_period, self.core)
self.channel = channel
self.write_div = 0
self.read_div = 0
# a full transfer takes prep_mu + xfer_mu
self.prep_mu = 0
# chained transfers can happen every xfer_mu
self.xfer_mu = 0
# The second transfer of a chain be written ref_period_mu
# after the first. Read data is available every xfer_mu starting
# a bit before prep_mu + xfer_mu.
self.write_period_mu = 0
self.read_period_mu = 0
self.xfer_period_mu = 0
# A full transfer takes write_period_mu + xfer_period_mu.
# Chained transfers can happen every xfer_period_mu.
# The second transfer of a chain can be written 2*ref_period_mu
# after the first. Read data is available every xfer_period_mu starting
# a bit after xfer_period_mu (depending on clk_phase).
# To chain transfers together, new data must be written before
# pending transfer's read data becomes available.

@portable
def predict_xfer_mu(self, write_length, read_length):
# this is only the intrinsic bit cycle duration
return int(self.ref_period_mu*(
write_length*self.write_div +
read_length*self.read_div))

@portable
def predict_prep_mu(self, write_div):
return int(self.ref_period_mu*(
2 + # intermediate transfers
# one write_div for the wait+idle cycle
self.write_div))
@kernel
def set_config(self, flags=0, write_freq=20*MHz, read_freq=20*MHz):
write_div = round(1/(write_freq*self.ref_period))
read_div = round(1/(read_freq*self.ref_period))
self.set_config_mu(flags, write_div, read_div)

@kernel
def set_config(self, flags=0, write_div=6, read_div=6):
self.write_div = write_div
self.read_div = read_div
self.prep_mu = self.predict_prep_mu(write_div)
def set_config_mu(self, flags=0, write_div=6, read_div=6):
rt2wb_write(now_mu(), self.channel, SPI_CONFIG_ADDR, flags |
((write_div - 2) << 8) | ((read_div - 2) << 20))
delay_mu(self.ref_period_mu)
((write_div - 2) << 16) | ((read_div - 2) << 24))
self.write_period_mu = int(write_div*self.ref_period_mu)
self.read_period_mu = int(read_div*self.ref_period_mu)
delay_mu(2*self.ref_period_mu)

@portable
def get_xfer_period_mu(self, write_length, read_length):
return int(write_length*self.write_period_mu +
read_length*self.read_period_mu)

@kernel
def set_xfer(self, chip_select=0, write_length=0, read_length=0):
self.xfer_mu = self.predict_xfer_mu(write_length, read_length)
rt2wb_write(now_mu(), self.channel, SPI_XFER_ADDR,
chip_select | (write_length << 16) | (read_length << 24))
delay_mu(self.ref_period_mu)
self.xfer_period_mu = self.get_xfer_period_mu(
write_length, read_length)
delay_mu(int(2*self.ref_period_mu))

@kernel
def write(self, data):
rt2wb_write(now_mu(), self.channel, SPI_DATA_ADDR, data)
delay_mu(int(self.prep_mu + self.xfer_mu))
delay_mu(int(self.write_period_mu + self.xfer_period_mu))

@kernel
def read_async(self):
rt2wb_write(now_mu(), self.channel, SPI_DATA_ADDR | SPI_RT2WB_READ, 0)
delay_mu(int(2*self.ref_period_mu))

@kernel
def read_sync(self):
r = rt2wb_read_sync(now_mu(), self.channel, SPI_DATA_ADDR |
SPI_RT2WB_READ, int(self.ref_period_mu))
delay_mu(self.ref_period_mu)
return r
return rt2wb_read_sync(now_mu(), self.channel, SPI_DATA_ADDR |
SPI_RT2WB_READ, int(2*self.ref_period_mu))

@kernel
def _get_config_sync(self):
return rt2wb_read_sync(now_mu(), self.channel, SPI_CONFIG_ADDR |
SPI_RT2WB_READ, int(2*self.ref_period_mu))

@kernel
def _get_xfer_sync(self):
return rt2wb_read_sync(now_mu(), self.channel, SPI_XFER_ADDR |
SPI_RT2WB_READ, int(2*self.ref_period_mu))
2 changes: 1 addition & 1 deletion artiq/gateware/rtio/phy/wishbone.py
Original file line number Diff line number Diff line change
@@ -39,6 +39,6 @@ def __init__(self, address_width, wb=None):
wb.cyc.eq(active),
wb.stb.eq(active),

self.rtlink.i.stb.eq(active & wb.ack & ~wb.we),
self.rtlink.i.stb.eq(wb.ack & ~wb.we),
self.rtlink.i.data.eq(wb.dat_r)
]
2 changes: 1 addition & 1 deletion artiq/gateware/spi.py
Original file line number Diff line number Diff line change
@@ -310,7 +310,7 @@ def __init__(self, pads, bus=None, data_width=32):
spi.div_read.eq(config.div_read),
]
self.sync += [
bus.ack.eq(~bus.we | ~pending | spi.done),
bus.ack.eq(bus.cyc & bus.stb & (~bus.we | ~pending | spi.done)),
If(wb_we,
Array([data_write, xfer.raw_bits(), config.raw_bits()
])[bus.adr].eq(bus.dat_w)
2 changes: 1 addition & 1 deletion artiq/runtime/Makefile
Original file line number Diff line number Diff line change
@@ -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 ttl.o dds.o rt2wb.o
bridge.o rtio.o ttl.o rt2wb.o dds.o

CFLAGS += -I$(LIBALLOC_DIRECTORY) \
-I$(MISOC_DIRECTORY)/software/include/dyld \
19 changes: 6 additions & 13 deletions artiq/runtime/dds.c
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
#include <stdio.h>

#include "artiq_personality.h"
#include "rtio.h"
#include "rt2wb.h"
#include "log.h"
#include "dds.h"

@@ -26,19 +26,14 @@
#endif

#define DDS_WRITE(addr, data) do { \
rtio_o_address_write(addr); \
rtio_o_data_write(data); \
rtio_o_timestamp_write(now); \
rtio_write_and_process_status(now, CONFIG_RTIO_DDS_CHANNEL); \
rt2wb_write(now, CONFIG_RTIO_DDS_CHANNEL, addr, data); \
now += DURATION_WRITE; \
} while(0)

void dds_init(long long int timestamp, int channel)
{
long long int now;

rtio_chan_sel_write(CONFIG_RTIO_DDS_CHANNEL);

now = timestamp - DURATION_INIT;

#ifdef CONFIG_DDS_ONEHOT_SEL
@@ -94,10 +89,10 @@ static void dds_set_one(long long int now, long long int ref_time, unsigned int
{
unsigned int channel_enc;

if(channel >= CONFIG_DDS_CHANNEL_COUNT) {
core_log("Attempted to set invalid DDS channel\n");
return;
}
if(channel >= CONFIG_DDS_CHANNEL_COUNT) {
core_log("Attempted to set invalid DDS channel\n");
return;
}
#ifdef CONFIG_DDS_ONEHOT_SEL
channel_enc = 1 << channel;
#else
@@ -190,7 +185,6 @@ void dds_batch_exit(void)

if(!batch_mode)
artiq_raise_from_c("DDSBatchError", "DDS batch error", 0, 0, 0);
rtio_chan_sel_write(CONFIG_RTIO_DDS_CHANNEL);
/* + FUD time */
now = batch_ref_time - batch_count*(DURATION_PROGRAM + DURATION_WRITE);
for(i=0;i<batch_count;i++) {
@@ -216,7 +210,6 @@ void dds_set(long long int timestamp, int channel,
batch[batch_count].amplitude = amplitude;
batch_count++;
} else {
rtio_chan_sel_write(CONFIG_RTIO_DDS_CHANNEL);
dds_set_one(timestamp - DURATION_PROGRAM, timestamp, channel, ftw, pow, phase_mode,
amplitude);
}
40 changes: 14 additions & 26 deletions artiq/runtime/rt2wb.c
Original file line number Diff line number Diff line change
@@ -8,40 +8,28 @@
void rt2wb_write(long long int timestamp, int channel, int addr,
unsigned int data)
{
rtio_chan_sel_write(channel);
rtio_o_address_write(addr);
rtio_o_data_write(data);
rtio_o_timestamp_write(timestamp);
rtio_write_and_process_status(timestamp, channel);
rtio_output(timestamp, channel, addr, data);
}


unsigned int rt2wb_read_sync(long long int timestamp, int channel,
int addr, int duration)
unsigned int rt2wb_read_sync(long long int timestamp, int channel, int addr,
int duration)
{
int status;
unsigned int data;
int status;

rt2wb_write(timestamp, channel, addr, 0);
rtio_output(timestamp, channel, addr, 0);

while((status = rtio_i_status_read())) {
if(status & RTIO_I_STATUS_OVERFLOW) {
rtio_i_overflow_reset_write(1);
artiq_raise_from_c("RTIOOverflow",
"RT2WB overflow on channel {0}",
status = rtio_input_wait(timestamp + duration, channel);
if (status & RTIO_I_STATUS_OVERFLOW)
artiq_raise_from_c("RTIOOverflow",
"RT2WB read overflow on channel {0}",
channel, 0, 0);
}
if(rtio_get_counter() >= timestamp + duration) {
/* check empty flag again to prevent race condition.
* now we are sure that the time limit has been exceeded.
*/
if(rtio_i_status_read() & RTIO_I_STATUS_EMPTY)
artiq_raise_from_c("InternalError",
"RT2WB read failed on channel {0}",
channel, 0, 0);
}
/* input FIFO is empty - keep waiting */
}
if (status & RTIO_I_STATUS_EMPTY)
artiq_raise_from_c("RTIOTimeout",
"RT2WB read timeout on channel {0}",
channel, 0, 0);

data = rtio_i_data_read();
rtio_i_re_write(1);
return data;
2 changes: 2 additions & 0 deletions artiq/runtime/rt2wb.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef __RT2WB_H
#define __RT2WB_H

#include "rtio.h"

void rt2wb_write(long long int timestamp, int channel, int address,
unsigned int data);
unsigned int rt2wb_read_sync(long long int timestamp, int channel, int address,
36 changes: 36 additions & 0 deletions artiq/runtime/rtio.c
Original file line number Diff line number Diff line change
@@ -39,6 +39,42 @@ void rtio_process_exceptional_status(int status, long long int timestamp, int ch
}
}


void rtio_output(long long int timestamp, int channel, unsigned int addr,
unsigned int data)
{
rtio_chan_sel_write(channel);
rtio_o_timestamp_write(timestamp);
rtio_o_address_write(addr);
rtio_o_data_write(data);
rtio_write_and_process_status(timestamp, channel);
}


int rtio_input_wait(long long int timeout, int channel)
{
int status;

rtio_chan_sel_write(channel);
while((status = rtio_i_status_read())) {
if(status & RTIO_I_STATUS_OVERFLOW) {
rtio_i_overflow_reset_write(1);
break;
}
if(rtio_get_counter() >= timeout) {
/* check empty flag again to prevent race condition.
* now we are sure that the time limit has been exceeded.
*/
status = rtio_i_status_read();
if(status & RTIO_I_STATUS_EMPTY)
break;
}
/* input FIFO is empty - keep waiting */
}
return status;
}


void rtio_log_va(long long int timestamp, const char *fmt, va_list args)
{
// This executes on the kernel CPU's stack, which is specifically designed
3 changes: 3 additions & 0 deletions artiq/runtime/rtio.h
Original file line number Diff line number Diff line change
@@ -17,6 +17,9 @@ long long int rtio_get_counter(void);
void rtio_process_exceptional_status(int status, long long int timestamp, int channel);
void rtio_log(long long int timestamp, const char *format, ...);
void rtio_log_va(long long int timestamp, const char *format, va_list args);
void rtio_output(long long int timestamp, int channel, unsigned int address,
unsigned int data);
int rtio_input_wait(long long int timeout, int channel);

static inline void rtio_write_and_process_status(long long int timestamp, int channel)
{
Loading