diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 0f3112af8..1ce29e05b 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -372,6 +372,7 @@ extern fn dma_retrieve(name: CSlice) -> DmaTrace { }) } +#[cfg(has_rtio)] extern fn dma_playback(timestamp: i64, ptr: i32) { 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 ()) { struct Attr { offset: usize, diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 0c95842ad..64fd1e4e4 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -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; -pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; -pub const RTIO_O_STATUS_SEQUENCE_ERROR: u8 = 4; -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; +#[cfg(has_rtio)] +mod imp { + use core::ptr::{read_volatile, write_volatile}; + use cslice::CSlice; -pub extern fn init() { - send(&RtioInitRequest); -} + use board::csr; + use ::send; + use kernel_proto::*; -pub extern fn get_counter() -> i64 { - unsafe { - csr::rtio::counter_update_write(1); - csr::rtio::counter_read() as i64 + pub const RTIO_O_STATUS_WAIT: u8 = 1; + pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; + pub const RTIO_O_STATUS_SEQUENCE_ERROR: u8 = 4; + 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 unsafe fn rtio_o_data_write(offset: usize, data: u32) { - write_volatile( - csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - offset) as isize), - 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 get_counter() -> i64 { + unsafe { + csr::rtio::counter_update_write(1); + csr::rtio::counter_read() as i64 } } -} -pub extern fn output_wide(timestamp: i64, channel: i32, addr: i32, data: CSlice) { - 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 _) + #[inline(always)] + pub unsafe fn rtio_o_data_write(offset: usize, data: u32) { + write_volatile( + csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - offset) as isize), + 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 {} } - csr::rtio::o_we_write(1); - let status = csr::rtio::o_status_read(); - if status != 0 { - process_exceptional_status(timestamp, channel, status); + 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 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; + 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); } } + } - if word != 0 { - rtio_o_data_write(0, word); + pub extern fn output_wide(timestamp: i64, channel: i32, addr: i32, data: CSlice) { + 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); + 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))] -pub fn log(_timestamp: i64, _data: &[u8]) {} +#[cfg(not(has_rtio))] +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) { + 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 { use ::send; use ::recv; use kernel_proto::*; - #[repr(C)] pub struct ChannelState(i32, i64); diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index a9c67178b..76436f3fe 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -1,8 +1,9 @@ -use session::{kern_acknowledge, kern_send}; -use rtio_mgt; -use kernel_proto as kern; use std::io; +use kernel_proto as kern; use sched::Io; +use session::{kern_acknowledge, kern_send}; +#[cfg(has_rtio)] +use rtio_mgt; #[cfg(has_drtio)] mod drtio_i2c { @@ -317,29 +318,35 @@ mod spi { pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result { match request { + #[cfg(has_rtio)] &kern::RtioInitRequest => { info!("resetting RTIO"); rtio_mgt::init_core(); kern_acknowledge() } + #[cfg(has_rtio)] &kern::DrtioChannelStateRequest { channel } => { let (fifo_space, last_timestamp) = rtio_mgt::drtio_dbg::get_channel_state(channel); kern_send(io, &kern::DrtioChannelStateReply { fifo_space: fifo_space, last_timestamp: last_timestamp }) } + #[cfg(has_rtio)] &kern::DrtioResetChannelStateRequest { channel } => { rtio_mgt::drtio_dbg::reset_channel_state(channel); kern_acknowledge() } + #[cfg(has_rtio)] &kern::DrtioGetFifoSpaceRequest { channel } => { rtio_mgt::drtio_dbg::get_fifo_space(channel); kern_acknowledge() } + #[cfg(has_rtio)] &kern::DrtioPacketCountRequest { 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 }) } + #[cfg(has_rtio)] &kern::DrtioFifoSpaceReqCountRequest { linkno } => { let cnt = rtio_mgt::drtio_dbg::get_fifo_space_req_count(linkno); kern_send(io, &kern::DrtioFifoSpaceReqCountReply { cnt: cnt }) diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index d08e01c29..efdf987fc 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -37,6 +37,7 @@ macro_rules! borrow_mut { mod config; mod ethmac; +#[cfg(has_rtio)] mod rtio_mgt; mod urc; @@ -123,6 +124,7 @@ fn startup() { let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); + #[cfg(has_rtio)] rtio_mgt::startup(&io); io.spawn(4096, mgmt::thread); io.spawn(16384, session::thread); diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index e7578d92c..8d35e450b 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -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 } -} diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index e28a620e4..a9e8578eb 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -3,19 +3,23 @@ use std::{mem, str}; use std::cell::{Cell, RefCell}; use std::io::{self, Read, Write}; use std::error::Error; -use {config, rtio_mgt, mailbox, rpc_queue, kernel}; -use cache::Cache; -use rtio_dma::Manager as DmaManager; +use byteorder::{ByteOrder, NetworkEndian}; + use urc::Urc; use sched::{ThreadHandle, Io}; use sched::{TcpListener, TcpStream}; -use byteorder::{ByteOrder, NetworkEndian}; 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 session_proto as host; use kernel_proto as kern; -use kern_hwreq; macro_rules! unexpected { ($($arg:tt)*) => { @@ -268,11 +272,17 @@ fn process_host_message(io: &Io, unexpected!("attempted to switch RTIO clock while a kernel was running") } - if rtio_mgt::crg::switch_clock(clk) { - host_write(stream, host::Reply::ClockSwitchCompleted) - } else { - host_write(stream, host::Reply::ClockSwitchFailed) + #[cfg(has_rtio)] + { + if rtio_mgt::crg::switch_clock(clk) { + 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) => @@ -365,9 +375,14 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, } 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 { &kern::Log(args) => { use std::fmt::Write; @@ -541,9 +556,12 @@ fn host_kernel_worker(io: &Io, return Err(io_error("watchdog expired")) } - if !rtio_mgt::crg::check() { - host_write(stream, host::Reply::ClockFailure)?; - return Err(io_error("RTIO clock failure")) + #[cfg(has_rtio)] + { + 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")) } - if !rtio_mgt::crg::check() { - return Err(io_error("RTIO clock failure")) + #[cfg(has_rtio)] + { + if !rtio_mgt::crg::check() { + return Err(io_error("RTIO clock failure")) + } } io.relinquish()?