forked from M-Labs/artiq
Merge branch 'master' into phaser
* master: runtime: replace a (deliberate) memory leak with an interner. compiler: disable remarks. runtime: rewrite i2c support code in Rust. runtime: rewrite rtio support code in Rust.
This commit is contained in:
commit
feb95bf3cf
|
@ -40,7 +40,7 @@ class Source:
|
||||||
return cls(source.Buffer(f.read(), filename, 1), engine=engine)
|
return cls(source.Buffer(f.read(), filename, 1), engine=engine)
|
||||||
|
|
||||||
class Module:
|
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.attribute_writeback = attribute_writeback
|
||||||
self.engine = src.engine
|
self.engine = src.engine
|
||||||
self.embedding_map = src.embedding_map
|
self.embedding_map = src.embedding_map
|
||||||
|
|
|
@ -3,8 +3,7 @@ from artiq.language.types import TInt64, TInt32, TNone
|
||||||
|
|
||||||
|
|
||||||
@syscall(flags={"nowrite"})
|
@syscall(flags={"nowrite"})
|
||||||
def rtio_output(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32
|
def rtio_output(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32) -> TNone:
|
||||||
) -> TNone:
|
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -98,18 +98,18 @@ static mut API: &'static [(&'static str, *const ())] = &[
|
||||||
api!(cache_put = ::cache_put),
|
api!(cache_put = ::cache_put),
|
||||||
|
|
||||||
/* direct syscalls */
|
/* direct syscalls */
|
||||||
api!(rtio_init),
|
api!(rtio_init = ::rtio::init),
|
||||||
api!(rtio_get_counter),
|
api!(rtio_get_counter = ::rtio::get_counter),
|
||||||
api!(rtio_log),
|
api!(rtio_log),
|
||||||
api!(rtio_output),
|
api!(rtio_output = ::rtio::output),
|
||||||
api!(rtio_input_timestamp),
|
api!(rtio_input_timestamp = ::rtio::input_timestamp),
|
||||||
api!(rtio_input_data),
|
api!(rtio_input_data = ::rtio::input_data),
|
||||||
|
|
||||||
api!(i2c_init),
|
api!(i2c_init = ::i2c::init),
|
||||||
api!(i2c_start),
|
api!(i2c_start = ::i2c::start),
|
||||||
api!(i2c_stop),
|
api!(i2c_stop = ::i2c::stop),
|
||||||
api!(i2c_write),
|
api!(i2c_write = ::i2c::write),
|
||||||
api!(i2c_read),
|
api!(i2c_read = ::i2c::read),
|
||||||
|
|
||||||
// #if (defined CONFIG_AD9154_CS)
|
// #if (defined CONFIG_AD9154_CS)
|
||||||
api!(ad9154_init),
|
api!(ad9154_init),
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -23,6 +23,35 @@ mod rpc_proto;
|
||||||
mod dyld;
|
mod dyld;
|
||||||
mod api;
|
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;
|
||||||
|
mod i2c;
|
||||||
|
|
||||||
use core::{mem, ptr, slice, str};
|
use core::{mem, ptr, slice, str};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use libc::{c_char, size_t};
|
use libc::{c_char, size_t};
|
||||||
|
@ -91,12 +120,17 @@ extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -
|
||||||
static mut NOW: u64 = 0;
|
static mut NOW: u64 = 0;
|
||||||
|
|
||||||
#[no_mangle]
|
#[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 {
|
send(&LogSlice(unsafe {
|
||||||
str::from_utf8_unchecked(slice::from_raw_parts(ptr, len))
|
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() -> ! {
|
extern fn abort() -> ! {
|
||||||
println!("kernel called abort()");
|
println!("kernel called abort()");
|
||||||
send(&RunAborted);
|
send(&RunAborted);
|
||||||
|
@ -151,28 +185,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]
|
#[no_mangle]
|
||||||
pub extern fn __artiq_terminate(exception: *const kernel_proto::Exception,
|
pub extern fn __artiq_terminate(exception: *const kernel_proto::Exception,
|
||||||
backtrace_data: *mut usize,
|
backtrace_data: *mut usize,
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ pub struct Exception<'a> {
|
||||||
pub column: u32,
|
pub column: u32,
|
||||||
pub function: *const u8,
|
pub function: *const u8,
|
||||||
pub message: *const u8,
|
pub message: *const u8,
|
||||||
pub param: [u64; 3],
|
pub param: [i64; 3],
|
||||||
pub phantom: PhantomData<&'a str>
|
pub phantom: PhantomData<&'a str>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::prelude::v1::*;
|
||||||
use std::{mem, str};
|
use std::{mem, str};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::io::{self, Read, Write, BufWriter};
|
use std::io::{self, Read, Write, BufWriter};
|
||||||
|
use std::btree_set::BTreeSet;
|
||||||
use {config, rtio_crg, clock, mailbox, rpc_queue, kernel};
|
use {config, rtio_crg, clock, mailbox, rpc_queue, kernel};
|
||||||
use logger::BufferLogger;
|
use logger::BufferLogger;
|
||||||
use cache::Cache;
|
use cache::Cache;
|
||||||
|
@ -57,7 +58,8 @@ struct Session<'a> {
|
||||||
congress: &'a mut Congress,
|
congress: &'a mut Congress,
|
||||||
kernel_state: KernelState,
|
kernel_state: KernelState,
|
||||||
watchdog_set: clock::WatchdogSet,
|
watchdog_set: clock::WatchdogSet,
|
||||||
log_buffer: String
|
log_buffer: String,
|
||||||
|
interner: BTreeSet<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Session<'a> {
|
impl<'a> Session<'a> {
|
||||||
|
@ -66,7 +68,8 @@ impl<'a> Session<'a> {
|
||||||
congress: congress,
|
congress: congress,
|
||||||
kernel_state: KernelState::Absent,
|
kernel_state: KernelState::Absent,
|
||||||
watchdog_set: clock::WatchdogSet::new(),
|
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.
|
// FIXME: gross.
|
||||||
fn into_c_str(s: String) -> *const u8 {
|
fn into_c_str(interner: &mut BTreeSet<String>, s: String) -> *const u8 {
|
||||||
let s = s + "\0";
|
let s = s + "\0";
|
||||||
let p = s.as_bytes().as_ptr();
|
interner.insert(s.clone());
|
||||||
mem::forget(s);
|
let p = interner.get(&s).unwrap().as_bytes().as_ptr();
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
let exn = kern::Exception {
|
let exn = kern::Exception {
|
||||||
name: into_c_str(name),
|
name: into_c_str(&mut session.interner, name),
|
||||||
message: into_c_str(message),
|
message: into_c_str(&mut session.interner, message),
|
||||||
param: param,
|
param: param,
|
||||||
file: into_c_str(file),
|
file: into_c_str(&mut session.interner, file),
|
||||||
line: line,
|
line: line,
|
||||||
column: column,
|
column: column,
|
||||||
function: into_c_str(function),
|
function: into_c_str(&mut session.interner, function),
|
||||||
phantom: ::core::marker::PhantomData
|
phantom: ::core::marker::PhantomData
|
||||||
};
|
};
|
||||||
try!(kern_send(waiter, &kern::RpcRecvReply(Err(exn))));
|
try!(kern_send(waiter, &kern::RpcRecvReply(Err(exn))));
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub enum Request {
|
||||||
RpcException {
|
RpcException {
|
||||||
name: String,
|
name: String,
|
||||||
message: String,
|
message: String,
|
||||||
param: [u64; 3],
|
param: [i64; 3],
|
||||||
file: String,
|
file: String,
|
||||||
line: u32,
|
line: u32,
|
||||||
column: u32,
|
column: u32,
|
||||||
|
@ -59,9 +59,9 @@ impl Request {
|
||||||
8 => Request::RpcException {
|
8 => Request::RpcException {
|
||||||
name: try!(read_string(reader)),
|
name: try!(read_string(reader)),
|
||||||
message: try!(read_string(reader)),
|
message: try!(read_string(reader)),
|
||||||
param: [try!(read_u64(reader)),
|
param: [try!(read_u64(reader).map(|x| x as i64)),
|
||||||
try!(read_u64(reader)),
|
try!(read_u64(reader).map(|x| x as i64)),
|
||||||
try!(read_u64(reader))],
|
try!(read_u64(reader).map(|x| x as i64))],
|
||||||
file: try!(read_string(reader)),
|
file: try!(read_string(reader)),
|
||||||
line: try!(read_u32(reader)),
|
line: try!(read_u32(reader)),
|
||||||
column: try!(read_u32(reader)),
|
column: try!(read_u32(reader)),
|
||||||
|
@ -99,7 +99,7 @@ pub enum Reply<'a> {
|
||||||
KernelException {
|
KernelException {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
message: &'a str,
|
message: &'a str,
|
||||||
param: [u64; 3],
|
param: [i64; 3],
|
||||||
file: &'a str,
|
file: &'a str,
|
||||||
line: u32,
|
line: u32,
|
||||||
column: u32,
|
column: u32,
|
||||||
|
@ -157,9 +157,9 @@ impl<'a> Reply<'a> {
|
||||||
try!(write_u8(writer, 9));
|
try!(write_u8(writer, 9));
|
||||||
try!(write_string(writer, name));
|
try!(write_string(writer, name));
|
||||||
try!(write_string(writer, message));
|
try!(write_string(writer, message));
|
||||||
try!(write_u64(writer, param[0]));
|
try!(write_u64(writer, param[0] as u64));
|
||||||
try!(write_u64(writer, param[1]));
|
try!(write_u64(writer, param[1] as u64));
|
||||||
try!(write_u64(writer, param[2]));
|
try!(write_u64(writer, param[2] as u64));
|
||||||
try!(write_string(writer, file));
|
try!(write_string(writer, file));
|
||||||
try!(write_u32(writer, line));
|
try!(write_u32(writer, line));
|
||||||
try!(write_u32(writer, column));
|
try!(write_u32(writer, column));
|
||||||
|
|
|
@ -4,7 +4,7 @@ include $(MISOC_DIRECTORY)/software/common.mak
|
||||||
PYTHON ?= python3.5
|
PYTHON ?= python3.5
|
||||||
|
|
||||||
OBJECTS := flash_storage.o main.o
|
OBJECTS := flash_storage.o main.o
|
||||||
OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o rtio.o i2c.o ad9154.o
|
OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o ad9154.o
|
||||||
|
|
||||||
RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug
|
RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug
|
||||||
CORE_IO_COMMIT := d40c593f42fafbac1ff3d827f6df96338b5b7d8b
|
CORE_IO_COMMIT := d40c593f42fafbac1ff3d827f6df96338b5b7d8b
|
||||||
|
|
|
@ -1,192 +0,0 @@
|
||||||
#include <generated/csr.h>
|
|
||||||
|
|
||||||
#include "artiq_personality.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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -6,7 +6,8 @@
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
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_EXEC_ADDRESS 0x40800000
|
||||||
#define KERNELCPU_PAYLOAD_ADDRESS 0x40840000
|
#define KERNELCPU_PAYLOAD_ADDRESS 0x40840000
|
||||||
|
@ -16,20 +17,18 @@ void send_to_log(const char *ptr, size_t length);
|
||||||
/* called by libunwind */
|
/* called by libunwind */
|
||||||
int fprintf(FILE *stream, const char *fmt, ...)
|
int fprintf(FILE *stream, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
size_t size;
|
|
||||||
char *buf;
|
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
size = vsnprintf(NULL, 0, fmt, args);
|
size_t size = vsnprintf(NULL, 0, fmt, args);
|
||||||
buf = __builtin_alloca(size + 1);
|
char *buf = __builtin_alloca(size + 1);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vsnprintf(buf, size + 1, fmt, args);
|
vsnprintf(buf, size + 1, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
send_to_log(buf, size);
|
send_to_core_log(buf, size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,19 +102,35 @@ double round(double x)
|
||||||
int core_log(const char *fmt, ...);
|
int core_log(const char *fmt, ...);
|
||||||
int core_log(const char *fmt, ...)
|
int core_log(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
size_t size;
|
|
||||||
char *buf;
|
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
size = vsnprintf(NULL, 0, fmt, args);
|
size_t size = vsnprintf(NULL, 0, fmt, args);
|
||||||
buf = __builtin_alloca(size + 1);
|
char *buf = __builtin_alloca(size + 1);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vsnprintf(buf, size + 1, fmt, args);
|
vsnprintf(buf, size + 1, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
send_to_log(buf, size);
|
send_to_core_log(buf, size);
|
||||||
return 0;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -1,166 +0,0 @@
|
||||||
#include <generated/csr.h>
|
|
||||||
|
|
||||||
#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);
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
#ifndef __RTIO_H
|
|
||||||
#define __RTIO_H
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#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 */
|
|
Loading…
Reference in New Issue