irq commit: this large commit gets interrupts working
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
28
xous-kernel-riscv-rt/macros/Cargo.toml
Normal file
28
xous-kernel-riscv-rt/macros/Cargo.toml
Normal file
@ -0,0 +1,28 @@
|
||||
[package]
|
||||
authors = [
|
||||
"The RISC-V Team <risc-v@teams.rust-embedded.org>",
|
||||
"Jorge Aparicio <jorge@japaric.io>",
|
||||
]
|
||||
categories = ["embedded", "no-std"]
|
||||
description = "Attributes re-exported in `riscv-rt`"
|
||||
documentation = "https://docs.rs/riscv-rt"
|
||||
keywords = ["riscv", "runtime", "startup"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
name = "xous-kernel-riscv-rt-macros"
|
||||
repository = "https://github.com/rust-embedded/riscv-rt"
|
||||
version = "0.1.6"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "0.6.8"
|
||||
proc-macro2 = "0.4.20"
|
||||
|
||||
[dependencies.syn]
|
||||
features = ["extra-traits", "full"]
|
||||
version = "0.15.13"
|
||||
|
||||
[dependencies.rand]
|
||||
version = "0.5.5"
|
||||
default-features = false
|
210
xous-kernel-riscv-rt/macros/src/lib.rs
Normal file
210
xous-kernel-riscv-rt/macros/src/lib.rs
Normal file
@ -0,0 +1,210 @@
|
||||
#![deny(warnings)]
|
||||
|
||||
extern crate proc_macro;
|
||||
extern crate rand;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
extern crate core;
|
||||
extern crate proc_macro2;
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
|
||||
use proc_macro2::Span;
|
||||
use rand::Rng;
|
||||
use rand::SeedableRng;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use syn::{
|
||||
parse, spanned::Spanned, Ident, ItemFn, ReturnType, Type, Visibility,
|
||||
};
|
||||
|
||||
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
/// Attribute to declare the entry point of the program
|
||||
///
|
||||
/// **IMPORTANT**: This attribute must appear exactly *once* in the dependency graph. Also, if you
|
||||
/// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
|
||||
/// private modules between the item and the root of the crate); if the item is in the root of the
|
||||
/// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer releases.
|
||||
///
|
||||
/// The specified function will be called by the reset handler *after* RAM has been initialized.
|
||||
/// If present, the FPU will also be enabled before the function is called.
|
||||
///
|
||||
/// The type of the specified function must be `[unsafe] fn() -> !` (never ending function)
|
||||
///
|
||||
/// # Properties
|
||||
///
|
||||
/// The entry point will be called by the reset handler.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// - Simple entry point
|
||||
///
|
||||
/// ``` no_run
|
||||
/// #![no_main]
|
||||
/// use xous_riscv_rt::entry;
|
||||
/// #[entry]
|
||||
/// fn main() -> ! {
|
||||
/// loop {
|
||||
/// /* .. */
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn xous_kernel_entry(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let f = parse_macro_input!(input as ItemFn);
|
||||
|
||||
// check the function signature
|
||||
let valid_signature = f.constness.is_none()
|
||||
&& f.vis == Visibility::Inherited
|
||||
&& f.abi.is_none()
|
||||
&& f.decl.inputs.is_empty()
|
||||
&& f.decl.generics.params.is_empty()
|
||||
&& f.decl.generics.where_clause.is_none()
|
||||
&& f.decl.variadic.is_none()
|
||||
&& match f.decl.output {
|
||||
ReturnType::Default => false,
|
||||
ReturnType::Type(_, ref ty) => match **ty {
|
||||
Type::Never(_) => true,
|
||||
_ => false,
|
||||
},
|
||||
};
|
||||
|
||||
if !valid_signature {
|
||||
return parse::Error::new(
|
||||
f.span(),
|
||||
"`#[entry]` function must have signature `[unsafe] fn() -> !`",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
if !args.is_empty() {
|
||||
return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
// XXX should we blacklist other attributes?
|
||||
let attrs = f.attrs;
|
||||
let unsafety = f.unsafety;
|
||||
let hash = random_ident();
|
||||
let stmts = f.block.stmts;
|
||||
|
||||
quote!(
|
||||
#[export_name = "xous_kernel_main"]
|
||||
#(#attrs)*
|
||||
pub #unsafety fn #hash() -> ! {
|
||||
#(#stmts)*
|
||||
}
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Attribute to mark which function will be called at the beginning of the reset handler.
|
||||
///
|
||||
/// **IMPORTANT**: This attribute can appear at most *once* in the dependency graph. Also, if you
|
||||
/// are using Rust 1.30 the attribute must be used on a reachable item (i.e. there must be no
|
||||
/// private modules between the item and the root of the crate); if the item is in the root of the
|
||||
/// crate you'll be fine. This reachability restriction doesn't apply to Rust 1.31 and newer
|
||||
/// releases.
|
||||
///
|
||||
/// The function must have the signature of `unsafe fn()`.
|
||||
///
|
||||
/// The function passed will be called before static variables are initialized. Any access of static
|
||||
/// variables will result in undefined behavior.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use riscv_rt_macros::pre_init;
|
||||
/// #[pre_init]
|
||||
/// unsafe fn before_main() {
|
||||
/// // do something here
|
||||
/// }
|
||||
///
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let f = parse_macro_input!(input as ItemFn);
|
||||
|
||||
// check the function signature
|
||||
let valid_signature = f.constness.is_none()
|
||||
&& f.vis == Visibility::Inherited
|
||||
&& f.unsafety.is_some()
|
||||
&& f.abi.is_none()
|
||||
&& f.decl.inputs.is_empty()
|
||||
&& f.decl.generics.params.is_empty()
|
||||
&& f.decl.generics.where_clause.is_none()
|
||||
&& f.decl.variadic.is_none()
|
||||
&& match f.decl.output {
|
||||
ReturnType::Default => true,
|
||||
ReturnType::Type(_, ref ty) => match **ty {
|
||||
Type::Tuple(ref tuple) => tuple.elems.is_empty(),
|
||||
_ => false,
|
||||
},
|
||||
};
|
||||
|
||||
if !valid_signature {
|
||||
return parse::Error::new(
|
||||
f.span(),
|
||||
"`#[pre_init]` function must have signature `unsafe fn()`",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
if !args.is_empty() {
|
||||
return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
// XXX should we blacklist other attributes?
|
||||
let attrs = f.attrs;
|
||||
let ident = f.ident;
|
||||
let block = f.block;
|
||||
|
||||
quote!(
|
||||
#[export_name = "__pre_init"]
|
||||
#(#attrs)*
|
||||
pub unsafe fn #ident() #block
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
// Creates a random identifier
|
||||
fn random_ident() -> Ident {
|
||||
let secs = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
let count: u64 = CALL_COUNT.fetch_add(1, Ordering::SeqCst) as u64;
|
||||
let mut seed: [u8; 16] = [0; 16];
|
||||
|
||||
for (i, v) in seed.iter_mut().take(8).enumerate() {
|
||||
*v = ((secs >> (i * 8)) & 0xFF) as u8
|
||||
}
|
||||
|
||||
for (i, v) in seed.iter_mut().skip(8).enumerate() {
|
||||
*v = ((count >> (i * 8)) & 0xFF) as u8
|
||||
}
|
||||
|
||||
let mut rng = rand::rngs::SmallRng::from_seed(seed);
|
||||
Ident::new(
|
||||
&(0..16)
|
||||
.map(|i| {
|
||||
if i == 0 || rng.gen() {
|
||||
('a' as u8 + rng.gen::<u8>() % 25) as char
|
||||
} else {
|
||||
('0' as u8 + rng.gen::<u8>() % 10) as char
|
||||
}
|
||||
})
|
||||
.collect::<String>(),
|
||||
Span::call_site(),
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user