From 9c18f1b55541d9f13ae84d901c331cd6722b27a3 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 29 Sep 2016 20:36:04 +0000 Subject: [PATCH] Rust: port clock, rtio_crg routines. --- artiq/runtime.rs/src/clock.rs | 77 +++++++++++++++++++++++++++++ artiq/runtime.rs/src/lib.rs | 5 +- artiq/runtime.rs/src/rtio_crg.rs | 47 ++++++++++++++++++ artiq/runtime.rs/src/session/mod.rs | 45 ++++++++++++++--- artiq/runtime/main.c | 8 +-- 5 files changed, 171 insertions(+), 11 deletions(-) create mode 100644 artiq/runtime.rs/src/clock.rs create mode 100644 artiq/runtime.rs/src/rtio_crg.rs diff --git a/artiq/runtime.rs/src/clock.rs b/artiq/runtime.rs/src/clock.rs new file mode 100644 index 000000000..5644f472c --- /dev/null +++ b/artiq/runtime.rs/src/clock.rs @@ -0,0 +1,77 @@ +use board::csr::timer0; + +const INIT: u64 = ::core::i64::MAX as u64; +const FREQ: u64 = ::board::csr::CONFIG_CLOCK_FREQUENCY as u64; + +pub fn init() { + unsafe { + timer0::en_write(0); + timer0::load_write(INIT); + timer0::reload_write(INIT); + timer0::en_write(1); + } +} + +pub fn get_ms() -> u64 { + unsafe { + timer0::update_value_write(1); + (INIT - timer0::value_read()) / (FREQ / 1_000) + } +} + +pub fn spin_us(interval: u64) { + unsafe { + timer0::update_value_write(1); + let threshold = timer0::value_read() - interval * (FREQ / 1_000_000); + while timer0::value_read() > threshold { + timer0::update_value_write(1) + } + } +} + +#[derive(Debug, Clone, Copy)] +struct Watchdog { + active: bool, + threshold: u64 +} + +pub const MAX_WATCHDOGS: usize = 16; + +#[derive(Debug)] +pub struct WatchdogSet { + watchdogs: [Watchdog; MAX_WATCHDOGS] +} + +impl WatchdogSet { + pub fn new() -> WatchdogSet { + WatchdogSet { + watchdogs: [Watchdog { active: false, threshold: 0 }; MAX_WATCHDOGS] + } + } + + pub fn set_ms(&mut self, interval: u64) -> Result { + for (index, watchdog) in self.watchdogs.iter_mut().enumerate() { + if !watchdog.active { + watchdog.active = true; + watchdog.threshold = get_ms() + interval; + return Ok(index) + } + } + + warn!("cannot add watchdog; all {} watchdogs used", MAX_WATCHDOGS); + Err(()) + } + + pub fn clear(&mut self, index: usize) { + if index < MAX_WATCHDOGS { + self.watchdogs[index].active = false + } + } + + pub fn expired(&self) -> bool { + self.watchdogs.iter() + .filter(|wd| wd.active) + .min_by_key(|wd| wd.threshold) + .map_or(false, |wd| get_ms() > wd.threshold) + } +} diff --git a/artiq/runtime.rs/src/lib.rs b/artiq/runtime.rs/src/lib.rs index 3c1c6ed32..edb7b06a2 100644 --- a/artiq/runtime.rs/src/lib.rs +++ b/artiq/runtime.rs/src/lib.rs @@ -15,6 +15,8 @@ use buffer_logger::BufferLogger; pub mod board; pub mod io; pub mod config; +pub mod clock; +pub mod rtio_crg; pub mod buffer_logger; pub mod session; @@ -28,7 +30,8 @@ pub unsafe extern fn rust_main() { static mut log_buffer: [u8; 4096] = [0; 4096]; BufferLogger::new(&mut log_buffer[..]) .register(move |logger| { - info!("Accepting network sessions in Rust."); + clock::init(); + rtio_crg::init(); network_init(); let mut scheduler = io::Scheduler::new(); diff --git a/artiq/runtime.rs/src/rtio_crg.rs b/artiq/runtime.rs/src/rtio_crg.rs new file mode 100644 index 000000000..b1867396d --- /dev/null +++ b/artiq/runtime.rs/src/rtio_crg.rs @@ -0,0 +1,47 @@ +use board::csr; +use {clock, config}; + +pub fn init() { + unsafe { csr::rtio_crg::pll_reset_write(0) } + + let mut opt = [b'i']; + let clk; + match config::read("startup_clock", &mut opt) { + Ok(0) | Ok(1) if &opt == b"i" => { + info!("startup RTIO clock: internal"); + clk = 0 + } + Ok(1) if &opt == b"e" => { + info!("startup RTIO clock: external"); + clk = 1 + } + _ => { + error!("unrecognized startup_clock configuration entry"); + clk = 0 + } + }; + + if !switch_clock(clk) { + error!("startup RTIO clock failed"); + warn!("this may cause the system initialization to fail"); + warn!("fix clocking and reset the device"); + } +} + +pub fn check() -> bool { + unsafe { csr::rtio_crg::pll_locked_read() != 0 } +} + +pub fn switch_clock(clk: u8) -> bool { + unsafe { + let cur_clk = csr::rtio_crg::clock_sel_read(); + if clk != cur_clk { + csr::rtio_crg::pll_reset_write(1); + csr::rtio_crg::clock_sel_write(clk); + csr::rtio_crg::pll_reset_write(0); + } + } + + clock::spin_us(150); + return check() +} diff --git a/artiq/runtime.rs/src/session/mod.rs b/artiq/runtime.rs/src/session/mod.rs index fca04c563..ae82ab8e5 100644 --- a/artiq/runtime.rs/src/session/mod.rs +++ b/artiq/runtime.rs/src/session/mod.rs @@ -1,7 +1,7 @@ use std::prelude::v1::*; use std::str; use std::io::{self, Read, ErrorKind}; -use config; +use {config, rtio_crg}; use self::protocol::*; mod protocol; @@ -26,14 +26,23 @@ extern { } impl Session { - pub fn start() -> Session { + pub fn new() -> Session { unsafe { kloader_stop(); } Session { kernel_state: KernelState::Absent } } - pub fn end(self) { + pub fn running(&self) -> bool { + match self.kernel_state { + KernelState::Absent | KernelState::Loaded => false, + KernelState::Running | KernelState::RpcWait => true + } + } +} + +impl Drop for Session { + fn drop(&mut self) { unsafe { kloader_stop(); watchdog_init(); @@ -55,10 +64,14 @@ fn check_magic(stream: &mut ::io::TcpStream) -> io::Result<()> { } fn handle_request(stream: &mut ::io::TcpStream, - logger: &::buffer_logger::BufferLogger) -> io::Result<()> { + logger: &::buffer_logger::BufferLogger, + session: &mut Session) -> io::Result<()> { fn read_request(stream: &mut ::io::TcpStream) -> io::Result { let request = try!(Request::read_from(stream)); - trace!("comm<-host {:?}", request); + match &request { + &Request::LoadLibrary(_) => trace!("comm<-host LoadLibrary(...)"), + _ => trace!("comm<-host {:?}", request) + } Ok(request) } @@ -71,6 +84,7 @@ fn handle_request(stream: &mut ::io::TcpStream, Request::Ident => write_reply(stream, Reply::Ident(::board::ident(&mut [0; 64]))), + // artiq_corelog Request::Log => { // Logging the packet with the log is inadvisable trace!("comm->host Log(...)"); @@ -84,6 +98,7 @@ fn handle_request(stream: &mut ::io::TcpStream, write_reply(stream, Reply::Log("")) } + // artiq_coreconfig Request::FlashRead { ref key } => { let value = config::read_to_end(key); write_reply(stream, Reply::FlashRead(&value)) @@ -106,6 +121,20 @@ fn handle_request(stream: &mut ::io::TcpStream, write_reply(stream, Reply::FlashOk) } + // artiq_run/artiq_master + Request::SwitchClock(clk) => { + if session.running() { + error!("attempted to switch RTIO clock while kernel was running"); + write_reply(stream, Reply::ClockSwitchFailed) + } else { + if rtio_crg::switch_clock(clk) { + write_reply(stream, Reply::ClockSwitchCompleted) + } else { + write_reply(stream, Reply::ClockSwitchFailed) + } + } + } + _ => unreachable!() } } @@ -113,8 +142,10 @@ fn handle_request(stream: &mut ::io::TcpStream, fn handle_requests(stream: &mut ::io::TcpStream, logger: &::buffer_logger::BufferLogger) -> io::Result<()> { try!(check_magic(stream)); + + let mut session = Session::new(); loop { - try!(handle_request(stream, logger)) + try!(handle_request(stream, logger, &mut session)) } } @@ -122,6 +153,8 @@ pub fn handler(waiter: ::io::Waiter, logger: &::buffer_logger::BufferLogger) { let addr = ::io::SocketAddr::new(::io::IP_ANY, 1381); let listener = ::io::TcpListener::bind(waiter, addr).unwrap(); + info!("accepting network sessions in Rust"); + loop { let (mut stream, addr) = listener.accept().unwrap(); info!("new connection from {:?}", addr); diff --git a/artiq/runtime/main.c b/artiq/runtime/main.c index 25e826200..70451bb73 100644 --- a/artiq/runtime/main.c +++ b/artiq/runtime/main.c @@ -206,6 +206,8 @@ static struct net_server_instance analyzer_inst = { static void regular_main(void) { + clock_init(); + rtiocrg_init(); session_startup_kernel(); puts("Accepting network sessions."); @@ -242,11 +244,9 @@ int main(void) puts("ARTIQ runtime built "__DATE__" "__TIME__"\n"); alloc_give(&_fheap, &_eheap - &_fheap); - clock_init(); - rtiocrg_init(); - rust_main(); - // regular_main(); + // rust_main(); + regular_main(); return 0; }