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: d5893d15fbc3
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: 5480099f1bbd
Choose a head ref
  • 12 commits
  • 11 files changed
  • 3 contributors

Commits on Feb 26, 2016

  1. Copy the full SHA
    a5bf502 View commit details
  2. Copy the full SHA
    313a696 View commit details

Commits on Feb 27, 2016

  1. Revert wrong parts of 6bd16e4.

    whitequark committed Feb 27, 2016

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    63e0c7c View commit details
  2. Copy the full SHA
    e421b22 View commit details
  3. Fix tests.

    whitequark committed Feb 27, 2016

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    8bbffab View commit details

Commits on Feb 28, 2016

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9a881aa View commit details
  2. 8
    Copy the full SHA
    8d7e92e View commit details
  3. spi: add runtime support

    jordens committed Feb 28, 2016
    Copy the full SHA
    d63a635 View commit details
  4. spi: add coredevice support

    jordens committed Feb 28, 2016
    Copy the full SHA
    8b2b278 View commit details
  5. Merge remote-tracking branch 'm-labs/master' into spimaster

    * m-labs/master:
      Fix tests.
      types.TypePrinter: don't waste screen space on empty attribute lists.
      Revert wrong parts of 6bd16e4.
      examples/notebook: cleanup, and fix spelling
      test/LoopbackCount: request correct devices
    jordens committed Feb 28, 2016
    Copy the full SHA
    a450490 View commit details

Commits on Feb 29, 2016

  1. Copy the full SHA
    9a1d6a5 View commit details
  2. Copy the full SHA
    5480099 View commit details
10 changes: 8 additions & 2 deletions artiq/compiler/types.py
Original file line number Diff line number Diff line change
@@ -703,12 +703,15 @@ def name(self, typ, depth=0, max_depth=1):
elif isinstance(typ, TInstance):
if typ in self.recurse_guard or depth >= max_depth:
return "<instance {}>".format(typ.name)
else:
elif len(typ.attributes) > 0:
self.recurse_guard.add(typ)
attrs = ",\n\t\t".join(["{}: {}".format(attr, self.name(typ.attributes[attr],
depth + 1))
for attr in typ.attributes])
return "<instance {} {{\n\t\t{}\n\t}}>".format(typ.name, attrs)
else:
self.recurse_guard.add(typ)
return "<instance {} {{}}>".format(typ.name)
elif isinstance(typ, TMono):
if typ.params == {}:
return typ.name
@@ -745,12 +748,15 @@ def name(self, typ, depth=0, max_depth=1):
elif isinstance(typ, (TConstructor, TExceptionConstructor)):
if typ in self.recurse_guard or depth >= max_depth:
return "<constructor {}>".format(typ.name)
else:
elif len(typ.attributes) > 0:
self.recurse_guard.add(typ)
attrs = ", ".join(["{}: {}".format(attr, self.name(typ.attributes[attr],
depth + 1))
for attr in typ.attributes])
return "<constructor {} {{{}}}>".format(typ.name, attrs)
else:
self.recurse_guard.add(typ)
return "<constructor {} {{}}>".format(typ.name)
elif isinstance(typ, TBuiltin):
return "<builtin {}>".format(typ.name)
elif isinstance(typ, TValue):
88 changes: 88 additions & 0 deletions artiq/coredevice/spi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
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")


SPI_DATA_ADDR, SPI_XFER_ADDR, SPI_CONFIG_ADDR = range(3)
(
SPI_OFFLINE,
SPI_ACTIVE,
SPI_PENDING,
SPI_CS_POLARITY,
SPI_CLK_POLARITY,
SPI_CLK_PHASE,
SPI_LSB_FIRST,
SPI_HALF_DUPLEX,
) = (1 << i for i in range(8))


class SPIMaster:
"""Core device Serial Peripheral Interface (SPI) bus master.
:param ref_period: clock period of the SPI core.
:param channel: channel number of the SPI bus to control.
"""
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.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)
# 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*(
write_length*self.write_div +
read_length*self.read_div)

@portable
def predict_prep_mu(self, write_div):
return 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_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))
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))
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)

@kernel
def read(self):
r = spi_read(now_mu(), self.channel, SPI_DATA_ADDR)
delay_mu(self.ref_period_mu)
return r
48 changes: 30 additions & 18 deletions artiq/gateware/spi.py
Original file line number Diff line number Diff line change
@@ -13,14 +13,21 @@ def __init__(self, width):
self.clk = Signal(reset=1)

cnt = Signal.like(self.load)
bias = Signal()
zero = Signal()
self.comb += [
self.edge.eq(cnt == 0),
zero.eq(cnt == 0),
self.edge.eq(zero & ~bias),
]
self.sync += [
cnt.eq(cnt - 1),
If(zero,
bias.eq(0),
).Else(
cnt.eq(cnt - 1),
),
If(self.edge,
cnt.eq(self.load[1:] +
(self.load[0] & self.bias)),
cnt.eq(self.load[1:]),
bias.eq(self.load[0] & (self.clk ^ self.bias)),
self.clk.eq(~self.clk),
)
]
@@ -143,7 +150,7 @@ def __init__(self, data_width, clock_width, bits_width):
).Else(
self.cg.load.eq(self.div_read),
),
self.cg.bias.eq(fsm.before_entering("SETUP")),
self.cg.bias.eq(self.clk_phase),
fsm.ce.eq(self.cg.edge),
self.cs.eq(~fsm.ongoing("IDLE")),
self.reg.ce.eq(self.cg.edge),
@@ -226,16 +233,18 @@ class SPIMaster(Module):
(1, 1): idle high, output on falling, input on rising
1 lsb_first: LSB is the first bit on the wire (reset=0)
1 half_duplex: 3-wire SPI, in/out on mosi (reset=0)
12 div_write: counter load value to divide this module's clock
to the SPI write clk. clk pulses are asymmetric
if the value is odd, favoring longer setup over hold times.
f_clk/f_spi_write == div_write + 2 (reset=0)
12 div_read: ditto for the read clock
8 undefined
8 div_write: counter load value to divide this module's clock
to the SPI write clk.
f_clk/f_spi_write == 2*(div_write + 1) (reset=0)
8 div_read: ditto for the read clock
xfer (address 1):
16 cs: active high bit mask of chip selects to assert
8 write_len: 0-M bits
8 read_len: 0-M bits
6 write_len: 0-M bits
2 undefined
6 read_len: 0-M bits
2 undefined
data (address 0):
M write/read data
@@ -257,16 +266,19 @@ def __init__(self, pads, bus=None, data_width=32):
("clk_phase", 1),
("lsb_first", 1),
("half_duplex", 1),
("div_write", 12),
("div_read", 12),
("padding", 8),
("div_write", 8),
("div_read", 8),
])
config.offline.reset = 1
assert len(config) <= len(bus.dat_w)

xfer = Record([
("cs", 16),
("write_length", 8),
("read_length", 8),
("write_length", 6),
("padding0", 2),
("read_length", 6),
("padding1", 2),
])
assert len(xfer) <= len(bus.dat_w)

@@ -355,11 +367,11 @@ def __init__(self, pads, bus=None, data_width=32):


def SPI_DIV_WRITE(i):
return i << 8
return i << 16


def SPI_DIV_READ(i):
return i << 20
return i << 24


def SPI_CS(i):
1 change: 1 addition & 0 deletions artiq/gateware/targets/pipistrello.py
Original file line number Diff line number Diff line change
@@ -200,6 +200,7 @@ def __init__(self, cpu_type="or1k", **kwargs):
spi_pins.cs_n = pmod.d[3:]
phy = spi.SPIMaster(spi_pins)
self.submodules += phy
self.config["RTIO_SPI_CHANNEL"] = len(rtio_channels)
rtio_channels.append(rtio.Channel.from_phy(
phy, ofifo_depth=4, ififo_depth=4))

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
bridge.o rtio.o ttl.o dds.o spi.o

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

double round(double x);
@@ -121,6 +122,9 @@ static const struct symbol runtime_exports[] = {
{"dds_batch_exit", &dds_batch_exit},
{"dds_set", &dds_set},

{"spi_write", &spi_write},
{"spi_read", &spi_read},

{"cache_get", &cache_get},
{"cache_put", &cache_put},

50 changes: 50 additions & 0 deletions artiq/runtime/spi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <generated/csr.h>
#include <stdio.h>

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


#define DURATION_WRITE (1 << CONFIG_RTIO_FINE_TS_WIDTH)

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


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

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

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

#include <hw/common.h>
#include <generated/csr.h>
#include <generated/mem.h>

#define SPI_ADDR_DATA 0
#define SPI_ADDR_XFER 1
#define SPI_ADDR_CONFIG 2
#define SPI_WB_READ (1 << 2)

#define SPI_XFER_CS(x) (x)
#define SPI_XFER_WRITE_LENGTH(x) ((x) << 16)
#define SPI_XFER_READ_LENGTH(x) ((x) << 24)

void spi_write(long long int timestamp, int channel, int address, unsigned int data);
unsigned int spi_read(long long int timestamp, int channel, int address);

#endif /* __SPI_H */
3 changes: 2 additions & 1 deletion artiq/test/coredevice/test_rtio.py
Original file line number Diff line number Diff line change
@@ -104,7 +104,8 @@ def run(self):
class LoopbackCount(EnvExperiment):
def build(self):
self.setattr_device("core")
self.setattr_device("ttl_inout")
self.setattr_device("loop_in")
self.setattr_device("loop_out")
self.setattr_argument("npulses")

def set_count(self, count):
2 changes: 1 addition & 1 deletion artiq/test/lit/inferencer/error_with_self.py
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ def __exit__(self, n1, n2, n3):
def foo():
contextmgr.__enter__(1)
# CHECK-L: ${LINE:+3}: error: cannot unify <instance contextmgr> with int(width='a) while inferring the type for self argument
# CHECK-L: ${LINE:+2}: note: expression of type <instance contextmgr>
# CHECK-L: ${LINE:+2}: note: expression of type <instance contextmgr {}>
# CHECK-L: ${LINE:+1}: note: reference to an instance with a method '__enter__(self:int(width='a))->NoneType delay('b)'
with contextmgr():
pass
Loading