forked from M-Labs/artiq
1
0
Fork 0

runtime: allow #[cfg(not(has_rtio))] builds.

This commit is contained in:
whitequark 2017-11-03 15:49:12 +00:00
parent b3e920b3c8
commit 2404a0d8c8
6 changed files with 235 additions and 171 deletions

View File

@ -372,6 +372,7 @@ extern fn dma_retrieve(name: CSlice<u8>) -> DmaTrace {
}) })
} }
#[cfg(has_rtio)]
extern fn dma_playback(timestamp: i64, ptr: i32) { extern fn dma_playback(timestamp: i64, ptr: i32) {
assert!(ptr % 64 == 0); assert!(ptr % 64 == 0);
@ -404,6 +405,11 @@ extern fn dma_playback(timestamp: i64, ptr: i32) {
} }
} }
#[cfg(not(has_rtio))]
extern fn dma_playback(timestamp: i64, ptr: i32) {
unimplemented!("not(has_rtio)")
}
unsafe fn attribute_writeback(typeinfo: *const ()) { unsafe fn attribute_writeback(typeinfo: *const ()) {
struct Attr { struct Attr {
offset: usize, offset: usize,

View File

@ -1,168 +1,209 @@
use core::ptr::{read_volatile, write_volatile};
use cslice::CSlice;
use board::csr;
use ::send;
use kernel_proto::*;
pub const RTIO_O_STATUS_WAIT: u8 = 1; #[cfg(has_rtio)]
pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; mod imp {
pub const RTIO_O_STATUS_SEQUENCE_ERROR: u8 = 4; use core::ptr::{read_volatile, write_volatile};
pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1; use cslice::CSlice;
pub const RTIO_I_STATUS_OVERFLOW: u8 = 2;
pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4;
pub extern fn init() { use board::csr;
send(&RtioInitRequest); use ::send;
} use kernel_proto::*;
pub extern fn get_counter() -> i64 { pub const RTIO_O_STATUS_WAIT: u8 = 1;
unsafe { pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2;
csr::rtio::counter_update_write(1); pub const RTIO_O_STATUS_SEQUENCE_ERROR: u8 = 4;
csr::rtio::counter_read() as i64 pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1;
pub const RTIO_I_STATUS_OVERFLOW: u8 = 2;
pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4;
pub extern fn init() {
send(&RtioInitRequest);
} }
}
#[inline(always)] pub extern fn get_counter() -> i64 {
pub unsafe fn rtio_o_data_write(offset: usize, data: u32) { unsafe {
write_volatile( csr::rtio::counter_update_write(1);
csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - offset) as isize), csr::rtio::counter_read() as i64
data);
}
#[inline(always)]
pub unsafe fn rtio_i_data_read(offset: usize) -> u32 {
read_volatile(
csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1 - offset) as isize))
}
#[inline(never)]
unsafe fn process_exceptional_status(timestamp: i64, channel: i32, status: u8) {
if status & RTIO_O_STATUS_WAIT != 0 {
while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {}
}
if status & RTIO_O_STATUS_UNDERFLOW != 0 {
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 {
raise!("RTIOSequenceError",
"RTIO sequence error at {0} mu, channel {1}",
timestamp, channel as i64, 0)
}
}
pub extern fn output(timestamp: i64, channel: i32, addr: i32, data: i32) {
unsafe {
csr::rtio::chan_sel_write(channel as _);
// writing timestamp clears o_data
csr::rtio::timestamp_write(timestamp as u64);
csr::rtio::o_address_write(addr as _);
rtio_o_data_write(0, data as _);
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 output_wide(timestamp: i64, channel: i32, addr: i32, data: CSlice<i32>) { #[inline(always)]
unsafe { pub unsafe fn rtio_o_data_write(offset: usize, data: u32) {
csr::rtio::chan_sel_write(channel as _); write_volatile(
// writing timestamp clears o_data csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - offset) as isize),
csr::rtio::timestamp_write(timestamp as u64); data);
csr::rtio::o_address_write(addr as _); }
for i in 0..data.len() {
rtio_o_data_write(i, data[i] as _) #[inline(always)]
pub unsafe fn rtio_i_data_read(offset: usize) -> u32 {
read_volatile(
csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1 - offset) as isize))
}
#[inline(never)]
unsafe fn process_exceptional_status(timestamp: i64, channel: i32, status: u8) {
if status & RTIO_O_STATUS_WAIT != 0 {
while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {}
} }
csr::rtio::o_we_write(1); if status & RTIO_O_STATUS_UNDERFLOW != 0 {
let status = csr::rtio::o_status_read(); raise!("RTIOUnderflow",
if status != 0 { "RTIO underflow at {0} mu, channel {1}, slack {2} mu",
process_exceptional_status(timestamp, channel, status); timestamp, channel as i64, timestamp - get_counter())
}
if status & RTIO_O_STATUS_SEQUENCE_ERROR != 0 {
raise!("RTIOSequenceError",
"RTIO sequence error at {0} mu, channel {1}",
timestamp, channel as i64, 0)
} }
} }
}
pub extern fn input_timestamp(timeout: i64, channel: i32) -> u64 { pub extern fn output(timestamp: i64, channel: i32, addr: i32, data: i32) {
unsafe { unsafe {
csr::rtio::chan_sel_write(channel as _); csr::rtio::chan_sel_write(channel as _);
csr::rtio::timestamp_write(timeout as u64); // writing timestamp clears o_data
csr::rtio::i_request_write(1); csr::rtio::timestamp_write(timestamp as u64);
csr::rtio::o_address_write(addr as _);
let mut status = RTIO_I_STATUS_WAIT_STATUS; rtio_o_data_write(0, data as _);
while status & RTIO_I_STATUS_WAIT_STATUS != 0 { csr::rtio::o_we_write(1);
status = csr::rtio::i_status_read(); let status = csr::rtio::o_status_read();
} if status != 0 {
process_exceptional_status(timestamp, channel, status);
if status & RTIO_I_STATUS_OVERFLOW != 0 {
raise!("RTIOOverflow",
"RTIO input overflow on channel {0}",
channel as i64, 0, 0);
}
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
return !0
}
csr::rtio::i_timestamp_read()
}
}
pub extern fn input_data(channel: i32) -> i32 {
unsafe {
csr::rtio::chan_sel_write(channel as _);
csr::rtio::timestamp_write(0xffffffff_ffffffff);
csr::rtio::i_request_write(1);
let mut status = RTIO_I_STATUS_WAIT_STATUS;
while status & RTIO_I_STATUS_WAIT_STATUS != 0 {
status = csr::rtio::i_status_read();
}
if status & RTIO_I_STATUS_OVERFLOW != 0 {
csr::rtio::i_overflow_reset_write(1);
raise!("RTIOOverflow",
"RTIO input overflow on channel {0}",
channel as i64, 0, 0);
}
rtio_i_data_read(0) as i32
}
}
#[cfg(has_rtio_log)]
pub fn log(timestamp: i64, data: &[u8]) {
unsafe {
csr::rtio::chan_sel_write(csr::CONFIG_RTIO_LOG_CHANNEL);
csr::rtio::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 == 3 {
rtio_o_data_write(0, word);
csr::rtio::o_we_write(1);
word = 0;
} }
} }
}
if word != 0 { pub extern fn output_wide(timestamp: i64, channel: i32, addr: i32, data: CSlice<i32>) {
rtio_o_data_write(0, word); unsafe {
csr::rtio::chan_sel_write(channel as _);
// writing timestamp clears o_data
csr::rtio::timestamp_write(timestamp as u64);
csr::rtio::o_address_write(addr as _);
for i in 0..data.len() {
rtio_o_data_write(i, data[i] as _)
}
csr::rtio::o_we_write(1); 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: i32) -> u64 {
unsafe {
csr::rtio::chan_sel_write(channel as _);
csr::rtio::timestamp_write(timeout as u64);
csr::rtio::i_request_write(1);
let mut status = RTIO_I_STATUS_WAIT_STATUS;
while status & RTIO_I_STATUS_WAIT_STATUS != 0 {
status = csr::rtio::i_status_read();
}
if status & RTIO_I_STATUS_OVERFLOW != 0 {
raise!("RTIOOverflow",
"RTIO input overflow on channel {0}",
channel as i64, 0, 0);
}
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
return !0
}
csr::rtio::i_timestamp_read()
}
}
pub extern fn input_data(channel: i32) -> i32 {
unsafe {
csr::rtio::chan_sel_write(channel as _);
csr::rtio::timestamp_write(0xffffffff_ffffffff);
csr::rtio::i_request_write(1);
let mut status = RTIO_I_STATUS_WAIT_STATUS;
while status & RTIO_I_STATUS_WAIT_STATUS != 0 {
status = csr::rtio::i_status_read();
}
if status & RTIO_I_STATUS_OVERFLOW != 0 {
csr::rtio::i_overflow_reset_write(1);
raise!("RTIOOverflow",
"RTIO input overflow on channel {0}",
channel as i64, 0, 0);
}
rtio_i_data_read(0) as i32
}
}
#[cfg(has_rtio_log)]
pub fn log(timestamp: i64, data: &[u8]) {
unsafe {
csr::rtio::chan_sel_write(csr::CONFIG_RTIO_LOG_CHANNEL);
csr::rtio::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 == 3 {
rtio_o_data_write(0, word);
csr::rtio::o_we_write(1);
word = 0;
}
}
if word != 0 {
rtio_o_data_write(0, word);
csr::rtio::o_we_write(1);
}
}
}
#[cfg(not(has_rtio_log))]
pub fn log(_timestamp: i64, _data: &[u8]) {
unimplemented!("not(has_rtio_log)")
}
} }
#[cfg(not(has_rtio_log))] #[cfg(not(has_rtio))]
pub fn log(_timestamp: i64, _data: &[u8]) {} mod imp {
use cslice::CSlice;
pub extern fn init() {
unimplemented!("not(has_rtio)")
}
pub extern fn get_counter() -> i64 {
unimplemented!("not(has_rtio)")
}
pub extern fn output(_timestamp: i64, _channel: i32, _addr: i32, _data: i32) {
unimplemented!("not(has_rtio)")
}
pub extern fn output_wide(_timestamp: i64, _channel: i32, _addr: i32, _data: CSlice<i32>) {
unimplemented!("not(has_rtio)")
}
pub extern fn input_timestamp(_timeout: i64, _channel: i32) -> u64 {
unimplemented!("not(has_rtio)")
}
pub extern fn input_data(_channel: i32) -> i32 {
unimplemented!("not(has_rtio)")
}
pub fn log(_timestamp: i64, _data: &[u8]) {
unimplemented!("not(has_rtio)")
}
}
pub use self::imp::*;
pub mod drtio_dbg { pub mod drtio_dbg {
use ::send; use ::send;
use ::recv; use ::recv;
use kernel_proto::*; use kernel_proto::*;
#[repr(C)] #[repr(C)]
pub struct ChannelState(i32, i64); pub struct ChannelState(i32, i64);

View File

@ -1,8 +1,9 @@
use session::{kern_acknowledge, kern_send};
use rtio_mgt;
use kernel_proto as kern;
use std::io; use std::io;
use kernel_proto as kern;
use sched::Io; use sched::Io;
use session::{kern_acknowledge, kern_send};
#[cfg(has_rtio)]
use rtio_mgt;
#[cfg(has_drtio)] #[cfg(has_drtio)]
mod drtio_i2c { mod drtio_i2c {
@ -317,29 +318,35 @@ mod spi {
pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result<bool> { pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result<bool> {
match request { match request {
#[cfg(has_rtio)]
&kern::RtioInitRequest => { &kern::RtioInitRequest => {
info!("resetting RTIO"); info!("resetting RTIO");
rtio_mgt::init_core(); rtio_mgt::init_core();
kern_acknowledge() kern_acknowledge()
} }
#[cfg(has_rtio)]
&kern::DrtioChannelStateRequest { channel } => { &kern::DrtioChannelStateRequest { channel } => {
let (fifo_space, last_timestamp) = rtio_mgt::drtio_dbg::get_channel_state(channel); let (fifo_space, last_timestamp) = rtio_mgt::drtio_dbg::get_channel_state(channel);
kern_send(io, &kern::DrtioChannelStateReply { fifo_space: fifo_space, kern_send(io, &kern::DrtioChannelStateReply { fifo_space: fifo_space,
last_timestamp: last_timestamp }) last_timestamp: last_timestamp })
} }
#[cfg(has_rtio)]
&kern::DrtioResetChannelStateRequest { channel } => { &kern::DrtioResetChannelStateRequest { channel } => {
rtio_mgt::drtio_dbg::reset_channel_state(channel); rtio_mgt::drtio_dbg::reset_channel_state(channel);
kern_acknowledge() kern_acknowledge()
} }
#[cfg(has_rtio)]
&kern::DrtioGetFifoSpaceRequest { channel } => { &kern::DrtioGetFifoSpaceRequest { channel } => {
rtio_mgt::drtio_dbg::get_fifo_space(channel); rtio_mgt::drtio_dbg::get_fifo_space(channel);
kern_acknowledge() kern_acknowledge()
} }
#[cfg(has_rtio)]
&kern::DrtioPacketCountRequest { linkno } => { &kern::DrtioPacketCountRequest { linkno } => {
let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts(linkno); let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts(linkno);
kern_send(io, &kern::DrtioPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt }) kern_send(io, &kern::DrtioPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt })
} }
#[cfg(has_rtio)]
&kern::DrtioFifoSpaceReqCountRequest { linkno } => { &kern::DrtioFifoSpaceReqCountRequest { linkno } => {
let cnt = rtio_mgt::drtio_dbg::get_fifo_space_req_count(linkno); let cnt = rtio_mgt::drtio_dbg::get_fifo_space_req_count(linkno);
kern_send(io, &kern::DrtioFifoSpaceReqCountReply { cnt: cnt }) kern_send(io, &kern::DrtioFifoSpaceReqCountReply { cnt: cnt })

View File

@ -37,6 +37,7 @@ macro_rules! borrow_mut {
mod config; mod config;
mod ethmac; mod ethmac;
#[cfg(has_rtio)]
mod rtio_mgt; mod rtio_mgt;
mod urc; mod urc;
@ -123,6 +124,7 @@ fn startup() {
let mut scheduler = sched::Scheduler::new(); let mut scheduler = sched::Scheduler::new();
let io = scheduler.io(); let io = scheduler.io();
#[cfg(has_rtio)]
rtio_mgt::startup(&io); rtio_mgt::startup(&io);
io.spawn(4096, mgmt::thread); io.spawn(4096, mgmt::thread);
io.spawn(16384, session::thread); io.spawn(16384, session::thread);

View File

@ -303,16 +303,3 @@ pub mod drtio_dbg {
} }
} }
} }
#[cfg(not(has_drtio))]
pub mod drtio_dbg {
pub fn get_channel_state(_channel: u32) -> (u16, u64) { (0, 0) }
pub fn reset_channel_state(_channel: u32) {}
pub fn get_fifo_space(_channel: u32) {}
pub fn get_packet_counts(_linkno: u8) -> (u32, u32) { (0, 0) }
pub fn get_fifo_space_req_count(_linkno: u8) -> u32 { 0 }
}

View File

@ -3,19 +3,23 @@ use std::{mem, str};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
use std::error::Error; use std::error::Error;
use {config, rtio_mgt, mailbox, rpc_queue, kernel}; use byteorder::{ByteOrder, NetworkEndian};
use cache::Cache;
use rtio_dma::Manager as DmaManager;
use urc::Urc; use urc::Urc;
use sched::{ThreadHandle, Io}; use sched::{ThreadHandle, Io};
use sched::{TcpListener, TcpStream}; use sched::{TcpListener, TcpStream};
use byteorder::{ByteOrder, NetworkEndian};
use board; use board;
use {config, mailbox, rpc_queue, kernel};
#[cfg(has_rtio)]
use rtio_mgt;
use rtio_dma::Manager as DmaManager;
use cache::Cache;
#[cfg(has_rtio)]
use kern_hwreq;
use rpc_proto as rpc; use rpc_proto as rpc;
use session_proto as host; use session_proto as host;
use kernel_proto as kern; use kernel_proto as kern;
use kern_hwreq;
macro_rules! unexpected { macro_rules! unexpected {
($($arg:tt)*) => { ($($arg:tt)*) => {
@ -268,11 +272,17 @@ fn process_host_message(io: &Io,
unexpected!("attempted to switch RTIO clock while a kernel was running") unexpected!("attempted to switch RTIO clock while a kernel was running")
} }
if rtio_mgt::crg::switch_clock(clk) { #[cfg(has_rtio)]
host_write(stream, host::Reply::ClockSwitchCompleted) {
} else { if rtio_mgt::crg::switch_clock(clk) {
host_write(stream, host::Reply::ClockSwitchFailed) host_write(stream, host::Reply::ClockSwitchCompleted)
} else {
host_write(stream, host::Reply::ClockSwitchFailed)
}
} }
#[cfg(not(has_rtio))]
host_write(stream, host::Reply::ClockSwitchFailed)
} }
host::Request::LoadKernel(kernel) => host::Request::LoadKernel(kernel) =>
@ -365,9 +375,14 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>,
} }
kern_recv_dotrace(request); kern_recv_dotrace(request);
if kern_hwreq::process_kern_hwreq(io, request)? {
return Ok(false) #[cfg(has_rtio)]
{
if kern_hwreq::process_kern_hwreq(io, request)? {
return Ok(false)
}
} }
match request { match request {
&kern::Log(args) => { &kern::Log(args) => {
use std::fmt::Write; use std::fmt::Write;
@ -541,9 +556,12 @@ fn host_kernel_worker(io: &Io,
return Err(io_error("watchdog expired")) return Err(io_error("watchdog expired"))
} }
if !rtio_mgt::crg::check() { #[cfg(has_rtio)]
host_write(stream, host::Reply::ClockFailure)?; {
return Err(io_error("RTIO clock failure")) if !rtio_mgt::crg::check() {
host_write(stream, host::Reply::ClockFailure)?;
return Err(io_error("RTIO clock failure"))
}
} }
} }
@ -583,8 +601,11 @@ fn flash_kernel_worker(io: &Io,
return Err(io_error("watchdog expired")) return Err(io_error("watchdog expired"))
} }
if !rtio_mgt::crg::check() { #[cfg(has_rtio)]
return Err(io_error("RTIO clock failure")) {
if !rtio_mgt::crg::check() {
return Err(io_error("RTIO clock failure"))
}
} }
io.relinquish()? io.relinquish()?