From a825584ac037fbcbd98fc19e3db54e8607b8779d Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 17:09:58 +0000 Subject: [PATCH 1/4] runtime: rewrite rtio support code in Rust. --- artiq/coredevice/rtio.py | 3 +- artiq/runtime.rs/libksupport/api.rs | 10 +- artiq/runtime.rs/libksupport/lib.rs | 57 +++++---- artiq/runtime.rs/libksupport/rtio.rs | 148 +++++++++++++++++++++++ artiq/runtime.rs/src/kernel_proto.rs | 2 +- artiq/runtime.rs/src/session_proto.rs | 16 +-- artiq/runtime/Makefile | 2 +- artiq/runtime/ksupport_glue.c | 37 ++++-- artiq/runtime/rtio.c | 166 -------------------------- artiq/runtime/rtio.h | 33 ----- 10 files changed, 224 insertions(+), 250 deletions(-) create mode 100644 artiq/runtime.rs/libksupport/rtio.rs delete mode 100644 artiq/runtime/rtio.c delete mode 100644 artiq/runtime/rtio.h diff --git a/artiq/coredevice/rtio.py b/artiq/coredevice/rtio.py index f4d0e2c82..2f564dc4b 100644 --- a/artiq/coredevice/rtio.py +++ b/artiq/coredevice/rtio.py @@ -3,8 +3,7 @@ from artiq.language.types import TInt64, TInt32, TNone @syscall(flags={"nowrite"}) -def rtio_output(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32 - ) -> TNone: +def rtio_output(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32) -> TNone: raise NotImplementedError("syscall not simulated") diff --git a/artiq/runtime.rs/libksupport/api.rs b/artiq/runtime.rs/libksupport/api.rs index 82448c744..fd069d8c4 100644 --- a/artiq/runtime.rs/libksupport/api.rs +++ b/artiq/runtime.rs/libksupport/api.rs @@ -98,12 +98,12 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(cache_put = ::cache_put), /* direct syscalls */ - api!(rtio_init), - api!(rtio_get_counter), + api!(rtio_init = ::rtio::init), + api!(rtio_get_counter = ::rtio::get_counter), api!(rtio_log), - api!(rtio_output), - api!(rtio_input_timestamp), - api!(rtio_input_data), + api!(rtio_output = ::rtio::output), + api!(rtio_input_timestamp = ::rtio::input_timestamp), + api!(rtio_input_data = ::rtio::input_data), api!(i2c_init), api!(i2c_start), diff --git a/artiq/runtime.rs/libksupport/lib.rs b/artiq/runtime.rs/libksupport/lib.rs index 7e4d66b59..f46d5efaf 100644 --- a/artiq/runtime.rs/libksupport/lib.rs +++ b/artiq/runtime.rs/libksupport/lib.rs @@ -23,6 +23,34 @@ mod rpc_proto; mod dyld; mod api; +#[allow(improper_ctypes)] +extern { + fn __artiq_raise(exn: *const ::kernel_proto::Exception) -> !; +} + +macro_rules! artiq_raise { + ($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => ({ + let exn = $crate::kernel_proto::Exception { + name: concat!("0:artiq.coredevice.exceptions.", $name, "\0").as_bytes().as_ptr(), + file: concat!(file!(), "\0").as_bytes().as_ptr(), + line: line!(), + column: column!(), + // https://github.com/rust-lang/rfcs/pull/1719 + function: "(Rust function)\0".as_bytes().as_ptr(), + message: concat!($message, "\0").as_bytes().as_ptr(), + param: [$param0, $param1, $param2], + phantom: ::core::marker::PhantomData + }; + #[allow(unused_unsafe)] + unsafe { $crate::__artiq_raise(&exn as *const _) } + }); + ($name:expr, $message:expr) => ({ + artiq_raise!($name, $message, 0, 0, 0) + }); +} + +mod rtio; + use core::{mem, ptr, slice, str}; use std::io::Cursor; use libc::{c_char, size_t}; @@ -91,12 +119,17 @@ extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) - static mut NOW: u64 = 0; #[no_mangle] -pub extern fn send_to_log(ptr: *const u8, len: usize) { +pub extern fn send_to_core_log(ptr: *const u8, len: usize) { send(&LogSlice(unsafe { str::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) })) } +#[no_mangle] +pub extern fn send_to_rtio_log(timestamp: i64, ptr: *const u8, len: usize) { + rtio::log(timestamp, unsafe { slice::from_raw_parts(ptr, len) }) +} + extern fn abort() -> ! { println!("kernel called abort()"); send(&RunAborted); @@ -151,28 +184,6 @@ extern fn recv_rpc(slot: *mut ()) -> usize { }) } -#[allow(improper_ctypes)] -extern { - fn __artiq_raise(exn: *const ::kernel_proto::Exception) -> !; -} - -macro_rules! artiq_raise { - ($name:expr, $message:expr) => ({ - let exn = Exception { - name: concat!("0:artiq.coredevice.exceptions.", $name, "\0").as_bytes().as_ptr(), - file: concat!(file!(), "\0").as_bytes().as_ptr(), - line: line!(), - column: column!(), - // https://github.com/rust-lang/rfcs/pull/1719 - function: "(Rust function)\0".as_bytes().as_ptr(), - message: concat!($message, "\0").as_bytes().as_ptr(), - param: [0; 3], - phantom: ::core::marker::PhantomData - }; - unsafe { __artiq_raise(&exn as *const _) } - }) -} - #[no_mangle] pub extern fn __artiq_terminate(exception: *const kernel_proto::Exception, backtrace_data: *mut usize, diff --git a/artiq/runtime.rs/libksupport/rtio.rs b/artiq/runtime.rs/libksupport/rtio.rs new file mode 100644 index 000000000..107583da4 --- /dev/null +++ b/artiq/runtime.rs/libksupport/rtio.rs @@ -0,0 +1,148 @@ +use board::csr; + +const RTIO_O_STATUS_FULL: u32 = 1; +const RTIO_O_STATUS_UNDERFLOW: u32 = 2; +const RTIO_O_STATUS_SEQUENCE_ERROR: u32 = 4; +const RTIO_O_STATUS_COLLISION: u32 = 8; +const RTIO_O_STATUS_BUSY: u32 = 16; +const RTIO_I_STATUS_EMPTY: u32 = 1; +const RTIO_I_STATUS_OVERFLOW: u32 = 2; + +pub extern fn init() { + unsafe { + csr::rtio::reset_write(1); + csr::rtio::reset_write(0); + csr::rtio::reset_phy_write(0); + } +} + +pub extern fn get_counter() -> i64 { + unsafe { + csr::rtio::counter_update_write(1); + csr::rtio::counter_read() as i64 + } +} + +#[inline(never)] +unsafe fn process_exceptional_status(timestamp: i64, channel: u32, status: u32) { + if status & RTIO_O_STATUS_FULL != 0 { + while csr::rtio::o_status_read() & RTIO_O_STATUS_FULL != 0 {} + } + if status & RTIO_O_STATUS_UNDERFLOW != 0 { + csr::rtio::o_underflow_reset_write(1); + artiq_raise!("RTIOUnderflow", + "RTIO underflow at {0} mu, channel {1}, slack {2} mu", + timestamp, channel as i64, timestamp - get_counter()) + } + if status & RTIO_O_STATUS_SEQUENCE_ERROR != 0 { + csr::rtio::o_sequence_error_reset_write(1); + artiq_raise!("RTIOSequenceError", + "RTIO sequence error at {0} mu, channel {1}", + timestamp, channel as i64, 0) + } + if status & RTIO_O_STATUS_COLLISION != 0 { + csr::rtio::o_collision_reset_write(1); + artiq_raise!("RTIOCollision", + "RTIO collision at {0} mu, channel {1}", + timestamp, channel as i64, 0) + } + if status & RTIO_O_STATUS_BUSY != 0 { + csr::rtio::o_busy_reset_write(1); + artiq_raise!("RTIOBusy", + "RTIO busy on channel {0}", + channel as i64, 0, 0) + } +} + +pub extern fn output(timestamp: i64, channel: u32, addr: u32, data: u32) { + unsafe { + csr::rtio::chan_sel_write(channel); + csr::rtio::o_timestamp_write(timestamp as u64); + csr::rtio::o_address_write(addr); + csr::rtio::o_data_write(data); + csr::rtio::o_we_write(1); + let status = csr::rtio::o_status_read(); + if status != 0 { + process_exceptional_status(timestamp, channel, status); + } + } +} + +pub extern fn input_timestamp(timeout: i64, channel: u32) -> u64 { + unsafe { + csr::rtio::chan_sel_write(channel); + let mut status; + loop { + status = csr::rtio::i_status_read(); + if status == 0 { break } + + if status & RTIO_I_STATUS_OVERFLOW != 0 { + csr::rtio::i_overflow_reset_write(1); + break + } + if get_counter() >= timeout { + // check empty flag again to prevent race condition. + // now we are sure that the time limit has been exceeded. + let status = csr::rtio::i_status_read(); + if status & RTIO_I_STATUS_EMPTY != 0 { break } + } + // input FIFO is empty - keep waiting + } + + if status & RTIO_I_STATUS_OVERFLOW != 0 { + artiq_raise!("RTIOOverflow", + "RTIO input overflow on channel {0}", + channel as i64, 0, 0); + } + if status & RTIO_I_STATUS_EMPTY != 0 { + return !0 + } + + let timestamp = csr::rtio::i_timestamp_read(); + csr::rtio::i_re_write(1); + timestamp + } +} + +pub extern fn input_data(channel: u32) -> u32 { + unsafe { + csr::rtio::chan_sel_write(channel); + loop { + let status = csr::rtio::i_status_read(); + if status == 0 { break } + + if status & RTIO_I_STATUS_OVERFLOW != 0 { + csr::rtio::i_overflow_reset_write(1); + artiq_raise!("RTIOOverflow", + "RTIO input overflow on channel {0}", + channel as i64, 0, 0); + } + } + + let data = csr::rtio::i_data_read(); + csr::rtio::i_re_write(1); + data + } +} + +pub fn log(timestamp: i64, data: &[u8]) { + unsafe { + csr::rtio::chan_sel_write(csr::CONFIG_RTIO_LOG_CHANNEL); + csr::rtio::o_timestamp_write(timestamp as u64); + + let mut word: u32 = 0; + for i in 0..data.len() { + word <<= 8; + word |= data[i] as u32; + if i % 4 == 0 { + csr::rtio::o_data_write(word); + csr::rtio::o_we_write(1); + word = 0; + } + } + + word <<= 8; + csr::rtio::o_data_write(word); + csr::rtio::o_we_write(1); + } +} diff --git a/artiq/runtime.rs/src/kernel_proto.rs b/artiq/runtime.rs/src/kernel_proto.rs index afaf7c35e..c015b76d2 100644 --- a/artiq/runtime.rs/src/kernel_proto.rs +++ b/artiq/runtime.rs/src/kernel_proto.rs @@ -17,7 +17,7 @@ pub struct Exception<'a> { pub column: u32, pub function: *const u8, pub message: *const u8, - pub param: [u64; 3], + pub param: [i64; 3], pub phantom: PhantomData<&'a str> } diff --git a/artiq/runtime.rs/src/session_proto.rs b/artiq/runtime.rs/src/session_proto.rs index fd48c46b3..e83b955f7 100644 --- a/artiq/runtime.rs/src/session_proto.rs +++ b/artiq/runtime.rs/src/session_proto.rs @@ -30,7 +30,7 @@ pub enum Request { RpcException { name: String, message: String, - param: [u64; 3], + param: [i64; 3], file: String, line: u32, column: u32, @@ -59,9 +59,9 @@ impl Request { 8 => Request::RpcException { name: try!(read_string(reader)), message: try!(read_string(reader)), - param: [try!(read_u64(reader)), - try!(read_u64(reader)), - try!(read_u64(reader))], + param: [try!(read_u64(reader).map(|x| x as i64)), + try!(read_u64(reader).map(|x| x as i64)), + try!(read_u64(reader).map(|x| x as i64))], file: try!(read_string(reader)), line: try!(read_u32(reader)), column: try!(read_u32(reader)), @@ -99,7 +99,7 @@ pub enum Reply<'a> { KernelException { name: &'a str, message: &'a str, - param: [u64; 3], + param: [i64; 3], file: &'a str, line: u32, column: u32, @@ -157,9 +157,9 @@ impl<'a> Reply<'a> { try!(write_u8(writer, 9)); try!(write_string(writer, name)); try!(write_string(writer, message)); - try!(write_u64(writer, param[0])); - try!(write_u64(writer, param[1])); - try!(write_u64(writer, param[2])); + try!(write_u64(writer, param[0] as u64)); + try!(write_u64(writer, param[1] as u64)); + try!(write_u64(writer, param[2] as u64)); try!(write_string(writer, file)); try!(write_u32(writer, line)); try!(write_u32(writer, column)); diff --git a/artiq/runtime/Makefile b/artiq/runtime/Makefile index 797123c2c..36685661c 100644 --- a/artiq/runtime/Makefile +++ b/artiq/runtime/Makefile @@ -4,7 +4,7 @@ include $(MISOC_DIRECTORY)/software/common.mak PYTHON ?= python3.5 OBJECTS := flash_storage.o main.o -OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o rtio.o i2c.o +OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o i2c.o RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug CORE_IO_COMMIT := d40c593f42fafbac1ff3d827f6df96338b5b7d8b diff --git a/artiq/runtime/ksupport_glue.c b/artiq/runtime/ksupport_glue.c index f0d496dc3..6525b4314 100644 --- a/artiq/runtime/ksupport_glue.c +++ b/artiq/runtime/ksupport_glue.c @@ -6,7 +6,8 @@ #include #include -void send_to_log(const char *ptr, size_t length); +void send_to_core_log(const char *ptr, size_t length); +void send_to_rtio_log(long long int timestamp, const char *ptr, size_t length); #define KERNELCPU_EXEC_ADDRESS 0x40800000 #define KERNELCPU_PAYLOAD_ADDRESS 0x40840000 @@ -16,20 +17,18 @@ void send_to_log(const char *ptr, size_t length); /* called by libunwind */ int fprintf(FILE *stream, const char *fmt, ...) { - size_t size; - char *buf; va_list args; va_start(args, fmt); - size = vsnprintf(NULL, 0, fmt, args); - buf = __builtin_alloca(size + 1); + size_t size = vsnprintf(NULL, 0, fmt, args); + char *buf = __builtin_alloca(size + 1); va_end(args); va_start(args, fmt); vsnprintf(buf, size + 1, fmt, args); va_end(args); - send_to_log(buf, size); + send_to_core_log(buf, size); return 0; } @@ -103,19 +102,35 @@ double round(double x) int core_log(const char *fmt, ...); int core_log(const char *fmt, ...) { - size_t size; - char *buf; va_list args; va_start(args, fmt); - size = vsnprintf(NULL, 0, fmt, args); - buf = __builtin_alloca(size + 1); + size_t size = vsnprintf(NULL, 0, fmt, args); + char *buf = __builtin_alloca(size + 1); va_end(args); va_start(args, fmt); vsnprintf(buf, size + 1, fmt, args); va_end(args); - send_to_log(buf, size); + send_to_core_log(buf, size); return 0; } + +/* called by kernel */ +void rtio_log(long long int timestamp, const char *fmt, ...); +void rtio_log(long long int timestamp, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + size_t size = vsnprintf(NULL, 0, fmt, args); + char *buf = __builtin_alloca(size + 1); + va_end(args); + + va_start(args, fmt); + vsnprintf(buf, size + 1, fmt, args); + va_end(args); + + send_to_rtio_log(timestamp, buf, size); +} diff --git a/artiq/runtime/rtio.c b/artiq/runtime/rtio.c deleted file mode 100644 index ac5168224..000000000 --- a/artiq/runtime/rtio.c +++ /dev/null @@ -1,166 +0,0 @@ -#include - -#include "artiq_personality.h" -#include "rtio.h" - -void rtio_init(void) -{ - rtio_reset_write(1); - rtio_reset_write(0); - rtio_reset_phy_write(0); -} - -long long int rtio_get_counter(void) -{ - rtio_counter_update_write(1); - return rtio_counter_read(); -} - -static void rtio_process_exceptional_status( - long long int timestamp, int channel, int status) -{ - if(status & RTIO_O_STATUS_FULL) - while(rtio_o_status_read() & RTIO_O_STATUS_FULL); - if(status & RTIO_O_STATUS_UNDERFLOW) { - rtio_o_underflow_reset_write(1); - artiq_raise_from_c("RTIOUnderflow", - "RTIO underflow at {0} mu, channel {1}, slack {2} mu", - timestamp, channel, timestamp - rtio_get_counter()); - } - if(status & RTIO_O_STATUS_SEQUENCE_ERROR) { - rtio_o_sequence_error_reset_write(1); - artiq_raise_from_c("RTIOSequenceError", - "RTIO sequence error at {0} mu, channel {1}", - timestamp, channel, 0); - } - if(status & RTIO_O_STATUS_COLLISION) { - rtio_o_collision_reset_write(1); - artiq_raise_from_c("RTIOCollision", - "RTIO collision at {0} mu, channel {1}", - timestamp, channel, 0); - } - if(status & RTIO_O_STATUS_BUSY) { - rtio_o_busy_reset_write(1); - artiq_raise_from_c("RTIOBusy", - "RTIO busy on channel {0}", - channel, 0, 0); - } -} - - -void rtio_output(long long int timestamp, int channel, unsigned int addr, - unsigned int data) -{ - int status; - - rtio_chan_sel_write(channel); - rtio_o_timestamp_write(timestamp); -#ifdef CSR_RTIO_O_ADDRESS_ADDR - rtio_o_address_write(addr); -#endif - rtio_o_data_write(data); - rtio_o_we_write(1); - status = rtio_o_status_read(); - if(status) - rtio_process_exceptional_status(timestamp, channel, status); -} - - -long long int rtio_input_timestamp(long long int timeout, int channel) -{ - long long int r; - 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 */ - } - - if (status & RTIO_I_STATUS_OVERFLOW) - artiq_raise_from_c("RTIOOverflow", - "RTIO input overflow on channel {0}", - channel, 0, 0); - if (status & RTIO_I_STATUS_EMPTY) - return -1; - - r = rtio_i_timestamp_read(); - rtio_i_re_write(1); - return r; -} - - -unsigned int rtio_input_data(int channel) -{ - unsigned int data; - 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); - artiq_raise_from_c("RTIOOverflow", - "RTIO input overflow on channel {0}", - channel, 0, 0); - } - } - - data = rtio_i_data_read(); - rtio_i_re_write(1); - return data; -} - - -void rtio_log_va(long long int timestamp, const char *fmt, va_list args) -{ -#ifdef CONFIG_RTIO_LOG_CHANNEL - // This executes on the kernel CPU's stack, which is specifically designed - // for allocation of this kind of massive buffers. - int len = vsnprintf(NULL, 0, fmt, args); - char *buf = __builtin_alloca(len + 1); - vsnprintf(buf, len + 1, fmt, args); - - rtio_chan_sel_write(CONFIG_RTIO_LOG_CHANNEL); - rtio_o_timestamp_write(timestamp); - - int i = 0; - unsigned int word = 0; - while(1) { - word <<= 8; - word |= *buf & 0xff; - if(*buf == 0) { - rtio_o_data_write(word); - rtio_o_we_write(1); - break; - } - buf++; - i++; - if(i == 4) { - rtio_o_data_write(word); - rtio_o_we_write(1); - word = 0; - i = 0; - } - } -#endif -} - -void rtio_log(long long int timestamp, const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - rtio_log_va(timestamp, fmt, args); - va_end(args); -} diff --git a/artiq/runtime/rtio.h b/artiq/runtime/rtio.h deleted file mode 100644 index aad6460ba..000000000 --- a/artiq/runtime/rtio.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __RTIO_H -#define __RTIO_H - -#include - -#define RTIO_O_STATUS_FULL 1 -#define RTIO_O_STATUS_UNDERFLOW 2 -#define RTIO_O_STATUS_SEQUENCE_ERROR 4 -#define RTIO_O_STATUS_COLLISION 8 -#define RTIO_O_STATUS_BUSY 16 -#define RTIO_I_STATUS_EMPTY 1 -#define RTIO_I_STATUS_OVERFLOW 2 - -void rtio_init(void); -long long int rtio_get_counter(void); -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); - -/* - * Waits at least until timeout and returns the timestamp of the first - * input event on the chanel, -1 if there was no event. - */ -long long int rtio_input_timestamp(long long int timeout, int channel); - -/* - * Assumes that there is or will be an event in the channel and returns only - * its data. - */ -unsigned int rtio_input_data(int channel); - -#endif /* __RTIO_H */ From 18b7ccea4e0eea63a4324bed3862883f14594ef4 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 18:25:43 +0000 Subject: [PATCH 2/4] runtime: rewrite i2c support code in Rust. --- artiq/runtime.rs/libksupport/api.rs | 10 +- artiq/runtime.rs/libksupport/i2c.rs | 166 ++++++++++++++++++++++++ artiq/runtime.rs/libksupport/lib.rs | 1 + artiq/runtime/Makefile | 2 +- artiq/runtime/i2c.c | 193 ---------------------------- artiq/runtime/i2c.h | 10 -- 6 files changed, 173 insertions(+), 209 deletions(-) create mode 100644 artiq/runtime.rs/libksupport/i2c.rs delete mode 100644 artiq/runtime/i2c.c delete mode 100644 artiq/runtime/i2c.h diff --git a/artiq/runtime.rs/libksupport/api.rs b/artiq/runtime.rs/libksupport/api.rs index fd069d8c4..5a12ea691 100644 --- a/artiq/runtime.rs/libksupport/api.rs +++ b/artiq/runtime.rs/libksupport/api.rs @@ -105,9 +105,9 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(rtio_input_timestamp = ::rtio::input_timestamp), api!(rtio_input_data = ::rtio::input_data), - api!(i2c_init), - api!(i2c_start), - api!(i2c_stop), - api!(i2c_write), - api!(i2c_read), + api!(i2c_init = ::i2c::init), + api!(i2c_start = ::i2c::start), + api!(i2c_stop = ::i2c::stop), + api!(i2c_write = ::i2c::write), + api!(i2c_read = ::i2c::read), ]; diff --git a/artiq/runtime.rs/libksupport/i2c.rs b/artiq/runtime.rs/libksupport/i2c.rs new file mode 100644 index 000000000..8a9f6da2d --- /dev/null +++ b/artiq/runtime.rs/libksupport/i2c.rs @@ -0,0 +1,166 @@ +use board::csr; + +fn half_period() { + unsafe { + csr::timer_kernel::en_write(0); + csr::timer_kernel::load_write(csr::CONFIG_CLOCK_FREQUENCY/10000); + csr::timer_kernel::reload_write(0); + csr::timer_kernel::en_write(1); + + csr::timer_kernel::update_value_write(1); + while csr::timer_kernel::value_read() != 0 { + csr::timer_kernel::update_value_write(1) + } + } +} + +#[cfg(has_i2c)] +mod imp { + use board::csr; + + fn sda_bit(busno: u32) -> u32 { 1 << (2 * busno + 1) } + fn scl_bit(busno: u32) -> u32 { 1 << (2 * busno) } + + pub fn sda_i(busno: u32) -> bool { + unsafe { + if busno >= csr::CONFIG_I2C_BUS_COUNT { + true + } else { + csr::i2c::in_read() & sda_bit(busno) != 0 + } + } + } + + pub fn sda_oe(busno: u32, oe: bool) { + unsafe { + let reg = csr::i2c::oe_read(); + let reg = if oe { reg | sda_bit(busno) } else { reg & !sda_bit(busno) }; + csr::i2c::oe_write(reg); + } + } + + pub fn sda_o(busno: u32, o: bool) { + unsafe { + let reg = csr::i2c::out_read(); + let reg = if o { reg | sda_bit(busno) } else { reg & !sda_bit(busno) }; + csr::i2c::out_write(reg) + } + } + + pub fn scl_oe(busno: u32, oe: bool) { + unsafe { + let reg = csr::i2c::oe_read(); + let reg = if oe { reg | scl_bit(busno) } else { reg & !scl_bit(busno) }; + csr::i2c::oe_write(reg) + } + } + + pub fn scl_o(busno: u32, o: bool) { + unsafe { + let reg = csr::i2c::out_read(); + let reg = if o { reg | scl_bit(busno) } else { reg & !scl_bit(busno) }; + csr::i2c::out_write(reg) + } + } +} + +// #[cfg(not(has_i2c))] +// mod imp { +// pub fn sda_i(busno: u32) -> bool { true } +// pub fn sda_oe(busno: u32, oe: bool) {} +// pub fn sda_o(busno: u32, o: bool) {} +// pub fn scl_oe(busno: u32, oe: bool) {} +// pub fn scl_o(busno: u32, o: bool) {} +// } + +use self::imp::*; + +pub extern fn init(busno: u32) { + // Set SCL as output, and high level + scl_o(busno, true); + scl_oe(busno, true); + // Prepare a zero level on SDA so that sda_oe pulls it down + sda_o(busno, false); + // Release SDA + sda_oe(busno, false); + + // Check the I2C bus is ready + half_period(); + half_period(); + if !sda_i(busno) { + artiq_raise!("I2CError", "SDA is stuck low") + } +} + +pub extern fn start(busno: u32) { + // Set SCL high then SDA low + scl_o(busno, true); + half_period(); + sda_oe(busno, true); + half_period(); +} + +pub extern fn stop(busno: u32) { + // First, make sure SCL is low, so that the target releases the SDA line + scl_o(busno, false); + half_period(); + // Set SCL high then SDA high + sda_oe(busno, true); + scl_o(busno, true); + half_period(); + sda_oe(busno, false); + half_period(); +} + +pub extern fn write(busno: u32, data: u8) -> bool { + // MSB first + for bit in (0..8).rev() { + // Set SCL low and set our bit on SDA + scl_o(busno, false); + sda_oe(busno, data & (1 << bit) == 0); + half_period(); + // Set SCL high ; data is shifted on the rising edge of SCL + scl_o(busno, true); + half_period(); + } + // Check ack + // Set SCL low, then release SDA so that the I2C target can respond + scl_o(busno, false); + half_period(); + sda_oe(busno, false); + // Set SCL high and check for ack + scl_o(busno, true); + half_period(); + // returns true if acked (I2C target pulled SDA low) + !sda_i(busno) +} + +pub extern fn read(busno: u32, ack: bool) -> u8 { + // Set SCL low first, otherwise setting SDA as input may cause a transition + // on SDA with SCL high which will be interpreted as START/STOP condition. + scl_o(busno, false); + half_period(); // make sure SCL has settled low + sda_oe(busno, false); + + let mut data: u8 = 0; + + // MSB first + for bit in (0..8).rev() { + scl_o(busno, false); + half_period(); + // Set SCL high and shift data + scl_o(busno, true); + half_period(); + if sda_i(busno) { data |= 1 << bit } + } + // Send ack + // Set SCL low and pull SDA low when acking + scl_o(busno, false); + if ack { sda_oe(busno, true) } + half_period(); + // then set SCL high + scl_o(busno, true); + half_period(); + + data +} diff --git a/artiq/runtime.rs/libksupport/lib.rs b/artiq/runtime.rs/libksupport/lib.rs index f46d5efaf..6b285f889 100644 --- a/artiq/runtime.rs/libksupport/lib.rs +++ b/artiq/runtime.rs/libksupport/lib.rs @@ -50,6 +50,7 @@ macro_rules! artiq_raise { } mod rtio; +mod i2c; use core::{mem, ptr, slice, str}; use std::io::Cursor; diff --git a/artiq/runtime/Makefile b/artiq/runtime/Makefile index 36685661c..a8387466b 100644 --- a/artiq/runtime/Makefile +++ b/artiq/runtime/Makefile @@ -4,7 +4,7 @@ include $(MISOC_DIRECTORY)/software/common.mak PYTHON ?= python3.5 OBJECTS := flash_storage.o main.o -OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o i2c.o +OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug CORE_IO_COMMIT := d40c593f42fafbac1ff3d827f6df96338b5b7d8b diff --git a/artiq/runtime/i2c.c b/artiq/runtime/i2c.c deleted file mode 100644 index c8ec3f131..000000000 --- a/artiq/runtime/i2c.c +++ /dev/null @@ -1,193 +0,0 @@ -#include - -#include "artiq_personality.h" -#include "rtio.h" -#include "i2c.h" - - -static void i2c_halfperiod() -{ - timer_kernel_en_write(0); - timer_kernel_load_write(CONFIG_CLOCK_FREQUENCY/10000); - timer_kernel_reload_write(0); - timer_kernel_en_write(1); - - timer_kernel_update_value_write(1); - while(timer_kernel_value_read() != 0) - timer_kernel_update_value_write(1); -} - -#if (defined CONFIG_I2C_BUS_COUNT) && (CONFIG_I2C_BUS_COUNT > 0) - -#define SDA_BIT (1 << (2*busno + 1)) -#define SCL_BIT (1 << (2*busno)) - -static int i2c_sda_i(int busno) -{ - if(busno >= CONFIG_I2C_BUS_COUNT) - return 1; - else - return i2c_in_read() & SDA_BIT; -} - -static void i2c_sda_oe(int busno, int oe) -{ - int reg; - - reg = i2c_oe_read(); - if(oe) - reg |= SDA_BIT; - else - reg &= ~SDA_BIT; - i2c_oe_write(reg); -} - -static void i2c_sda_o(int busno, int o) -{ - int reg; - - reg = i2c_out_read(); - if(o) - reg |= SDA_BIT; - else - reg &= ~SDA_BIT; - i2c_out_write(reg); -} - -static void i2c_scl_oe(int busno, int oe) -{ - int reg; - - reg = i2c_oe_read(); - if(oe) - reg |= SCL_BIT; - else - reg &= ~SCL_BIT; - i2c_oe_write(reg); -} - -static void i2c_scl_o(int busno, int o) -{ - int reg; - - reg = i2c_out_read(); - if(o) - reg |= SCL_BIT; - else - reg &= ~SCL_BIT; - i2c_out_write(reg); -} - -#else - -static int i2c_sda_i(int busno) -{ - return 1; -} -static void i2c_sda_oe(int busno, int oe) {} -static void i2c_sda_o(int busno, int o) {} -static void i2c_scl_oe(int busno, int oe) {} -static void i2c_scl_o(int busno, int o) {} - -#endif - - -void i2c_init(int busno) -{ - /* Set SCL as output, and high level */ - i2c_scl_o(busno, 1); - i2c_scl_oe(busno, 1); - /* Prepare a zero level on SDA so that i2c_sda_oe pulls it down */ - i2c_sda_o(busno, 0); - /* Release SDA */ - i2c_sda_oe(busno, 0); - - /* Check the I2C bus is ready */ - i2c_halfperiod(); - i2c_halfperiod(); - if(!i2c_sda_i(busno)) - artiq_raise_from_c("I2CError", "SDA is stuck low", 0, 0, 0); -} - -void i2c_start(int busno) -{ - /* Set SCL high then SDA low */ - i2c_scl_o(busno, 1); - i2c_halfperiod(); - i2c_sda_oe(busno, 1); - i2c_halfperiod(); -} - -void i2c_stop(int busno) -{ - /* First, make sure SCL is low, so that the target releases the SDA line */ - i2c_scl_o(busno, 0); - i2c_halfperiod(); - /* Set SCL high then SDA high */ - i2c_sda_oe(busno, 1); - i2c_scl_o(busno, 1); - i2c_halfperiod(); - i2c_sda_oe(busno, 0); - i2c_halfperiod(); -} - -int i2c_write(int busno, int b) -{ - int i; - - /* MSB first */ - for(i=7;i>=0;i--) { - /* Set SCL low and set our bit on SDA */ - i2c_scl_o(busno, 0); - i2c_sda_oe(busno, b & (1 << i) ? 0 : 1); - i2c_halfperiod(); - /* Set SCL high ; data is shifted on the rising edge of SCL */ - i2c_scl_o(busno, 1); - i2c_halfperiod(); - } - /* Check ack */ - /* Set SCL low, then release SDA so that the I2C target can respond */ - i2c_scl_o(busno, 0); - i2c_halfperiod(); - i2c_sda_oe(busno, 0); - /* Set SCL high and check for ack */ - i2c_scl_o(busno, 1); - i2c_halfperiod(); - /* returns 1 if acked (I2C target pulled SDA low) */ - return !i2c_sda_i(busno); -} - -int i2c_read(int busno, int ack) -{ - int i; - unsigned char b; - - /* Set SCL low first, otherwise setting SDA as input may cause a transition - * on SDA with SCL high which will be interpreted as START/STOP condition. - */ - i2c_scl_o(busno, 0); - i2c_halfperiod(); /* make sure SCL has settled low */ - i2c_sda_oe(busno, 0); - - b = 0; - /* MSB first */ - for(i=7;i>=0;i--) { - i2c_scl_o(busno, 0); - i2c_halfperiod(); - /* Set SCL high and shift data */ - i2c_scl_o(busno, 1); - i2c_halfperiod(); - if(i2c_sda_i(busno)) b |= (1 << i); - } - /* Send ack */ - /* Set SCL low and pull SDA low when acking */ - i2c_scl_o(busno, 0); - if(ack) - i2c_sda_oe(busno, 1); - i2c_halfperiod(); - /* then set SCL high */ - i2c_scl_o(busno, 1); - i2c_halfperiod(); - - return b; -} diff --git a/artiq/runtime/i2c.h b/artiq/runtime/i2c.h deleted file mode 100644 index c7aab6e22..000000000 --- a/artiq/runtime/i2c.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __I2C_H -#define __I2C_H - -void i2c_init(int busno); -void i2c_start(int busno); -void i2c_stop(int busno); -int i2c_write(int busno, int b); -int i2c_read(int busno, int ack); - -#endif From ac997daf957e8ff7a96bc7ab34bec288d8816733 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 19:12:11 +0000 Subject: [PATCH 3/4] compiler: disable remarks. --- artiq/compiler/module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py index d1d2b1efc..a11c8954e 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -40,7 +40,7 @@ class Source: return cls(source.Buffer(f.read(), filename, 1), engine=engine) class Module: - def __init__(self, src, ref_period=1e-6, attribute_writeback=True, remarks=True): + def __init__(self, src, ref_period=1e-6, attribute_writeback=True, remarks=False): self.attribute_writeback = attribute_writeback self.engine = src.engine self.embedding_map = src.embedding_map From 1d1e821a74734c101640af569ab3998ab5263037 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 19:47:56 +0000 Subject: [PATCH 4/4] runtime: replace a (deliberate) memory leak with an interner. --- artiq/runtime.rs/src/session.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/artiq/runtime.rs/src/session.rs b/artiq/runtime.rs/src/session.rs index 8589971a0..78eba0faa 100644 --- a/artiq/runtime.rs/src/session.rs +++ b/artiq/runtime.rs/src/session.rs @@ -2,6 +2,7 @@ use std::prelude::v1::*; use std::{mem, str}; use std::cell::RefCell; use std::io::{self, Read, Write, BufWriter}; +use std::btree_set::BTreeSet; use {config, rtio_crg, clock, mailbox, rpc_queue, kernel}; use logger::BufferLogger; use cache::Cache; @@ -57,7 +58,8 @@ struct Session<'a> { congress: &'a mut Congress, kernel_state: KernelState, watchdog_set: clock::WatchdogSet, - log_buffer: String + log_buffer: String, + interner: BTreeSet } impl<'a> Session<'a> { @@ -66,7 +68,8 @@ impl<'a> Session<'a> { congress: congress, kernel_state: KernelState::Absent, watchdog_set: clock::WatchdogSet::new(), - log_buffer: String::new() + log_buffer: String::new(), + interner: BTreeSet::new() } } @@ -309,20 +312,20 @@ fn process_host_message(waiter: Waiter, })); // FIXME: gross. - fn into_c_str(s: String) -> *const u8 { + fn into_c_str(interner: &mut BTreeSet, s: String) -> *const u8 { let s = s + "\0"; - let p = s.as_bytes().as_ptr(); - mem::forget(s); + interner.insert(s.clone()); + let p = interner.get(&s).unwrap().as_bytes().as_ptr(); p } let exn = kern::Exception { - name: into_c_str(name), - message: into_c_str(message), + name: into_c_str(&mut session.interner, name), + message: into_c_str(&mut session.interner, message), param: param, - file: into_c_str(file), + file: into_c_str(&mut session.interner, file), line: line, column: column, - function: into_c_str(function), + function: into_c_str(&mut session.interner, function), phantom: ::core::marker::PhantomData }; try!(kern_send(waiter, &kern::RpcRecvReply(Err(exn))));