Skip to content

Commit

Permalink
runtime: refactor spi into rt2wb
Browse files Browse the repository at this point in the history
jordens committed Feb 29, 2016
1 parent eb01b0b commit df7d15d
Showing 7 changed files with 60 additions and 67 deletions.
14 changes: 14 additions & 0 deletions artiq/coredevice/rt2wb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from artiq.language.core import *
from artiq.language.types import *


@syscall
def rt2wb_write(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32
) -> TNone:
raise NotImplementedError("syscall not simulated")


@syscall
def rt2wb_read_sync(time_mu: TInt64, channel: TInt32, addr: TInt32,
duration_mu: TInt32) -> TInt32:
raise NotImplementedError("syscall not simulated")
45 changes: 18 additions & 27 deletions artiq/coredevice/spi.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
from artiq.language.core import *
from artiq.language.types import *


@syscall
def spi_write(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32
) -> TNone:
raise NotImplementedError("syscall not simulated")


@syscall
def spi_read(time_mu: TInt64, channel: TInt32, addr: TInt32) -> TInt32:
raise NotImplementedError("syscall not simulated")
from artiq.coredevice.rt2wb import *


SPI_DATA_ADDR, SPI_XFER_ADDR, SPI_CONFIG_ADDR = range(3)
@@ -34,55 +24,56 @@ class SPIMaster:
"""
def __init__(self, dmgr, ref_period, channel):
self.core = dmgr.get("core")
self.ref_period_mu = int(seconds_to_mu(ref_period, self.core), 64)
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 = int(0, 64)
# chaned transfers can happen every xfer_mu
self.xfer_mu = int(0, 64)
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.

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

@portable
def predict_prep_mu(self, write_div):
return self.ref_period_mu*(
return int(self.ref_period_mu*(
2 + # intermediate transfers
# one write_div for the wait+idle cycle
self.write_div)
self.write_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)
spi_write(now_mu(), self.channel, SPI_CONFIG_ADDR, flags |
((write_div - 2) << 8) | ((read_div - 2) << 20))
rt2wb_write(now_mu(), self.channel, SPI_CONFIG_ADDR, flags |
((write_div - 2) << 8) | ((read_div - 2) << 20))
delay_mu(self.ref_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)
spi_write(now_mu(), self.channel, SPI_XFER_ADDR,
chip_select | (write_length << 16) | (read_length << 24))
rt2wb_write(now_mu(), self.channel, SPI_XFER_ADDR,
chip_select | (write_length << 16) | (read_length << 24))
delay_mu(self.ref_period_mu)

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

@kernel
def read(self):
r = spi_read(now_mu(), self.channel, SPI_DATA_ADDR)
def read_sync(self):
r = rt2wb_read_sync(now_mu(), self.channel, SPI_DATA_ADDR,
int(self.ref_period_mu))
delay_mu(self.ref_period_mu)
return r
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 spi.o
bridge.o rtio.o ttl.o dds.o rt2wb.o

CFLAGS += -I$(LIBALLOC_DIRECTORY) \
-I$(MISOC_DIRECTORY)/software/include/dyld \
6 changes: 3 additions & 3 deletions artiq/runtime/ksupport.c
Original file line number Diff line number Diff line change
@@ -15,8 +15,8 @@
#include "artiq_personality.h"
#include "ttl.h"
#include "dds.h"
#include "spi.h"
#include "rtio.h"
#include "rt2wb.h"

double round(double x);

@@ -122,8 +122,8 @@ static const struct symbol runtime_exports[] = {
{"dds_batch_exit", &dds_batch_exit},
{"dds_set", &dds_set},

{"spi_write", &spi_write},
{"spi_read", &spi_read},
{"rt2wb_write", &rt2wb_write},
{"rt2wb_read_sync", &rt2wb_read_sync},

{"cache_get", &cache_get},
{"cache_put", &cache_put},
30 changes: 14 additions & 16 deletions artiq/runtime/spi.c → artiq/runtime/rt2wb.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
#include <generated/csr.h>
#include <stdio.h>

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


#define DURATION_WRITE (1 << CONFIG_RTIO_FINE_TS_WIDTH)

void spi_write(long long int timestamp, int channel, int addr,
void rt2wb_write(long long int timestamp, int channel, int addr,
unsigned int data)
{
rtio_chan_sel_write(channel);
@@ -20,31 +16,33 @@ void spi_write(long long int timestamp, int channel, int addr,
}


unsigned int spi_read(long long int timestamp, int channel, int addr)
unsigned int rt2wb_read_sync(long long int timestamp, int channel,
int addr, int duration)
{
int status;
long long int time_limit = timestamp + DURATION_WRITE;
unsigned int r;
unsigned int data;

spi_write(timestamp, channel, addr | SPI_WB_READ, 0);
rt2wb_write(timestamp, channel, addr, 0);

while((status = rtio_i_status_read())) {
if(rtio_i_status_read() & RTIO_I_STATUS_OVERFLOW) {
if(status & RTIO_I_STATUS_OVERFLOW) {
rtio_i_overflow_reset_write(1);
artiq_raise_from_c("RTIOOverflow",
"RTIO overflow at channel {0}",
"RTIO WB overflow on channel {0}",
channel, 0, 0);
}
if(rtio_get_counter() >= time_limit) {
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)
return -1;
artiq_raise_from_c("InternalError",
"RTIO WB read failed on channel {0}",
channel, 0, 0);
}
/* input FIFO is empty - keep waiting */
}
r = rtio_i_data_read();
data = rtio_i_data_read();
rtio_i_re_write(1);
return r;
return data;
}
10 changes: 10 additions & 0 deletions artiq/runtime/rt2wb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef __RT2WB_H
#define __RT2WB_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,
int duration);

#endif /* __RT2WB_H */

20 changes: 0 additions & 20 deletions artiq/runtime/spi.h

This file was deleted.

4 comments on commit df7d15d

@sbourdeauducq
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wishbone is a gateware implementation detail. I would make it transparent to the Python layers.

@jordens
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RT2WB is not transparent because of how it handles reads. They can be pipelined or handled asynchronously.

@sbourdeauducq
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you going to rewrite the DDS code as well so it uses this, then?

@jordens
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Please sign in to comment.