mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-25 03:19:34 +01:00
Merge #151
151: make builds reproducible r=japaric a=japaric This is a rebased and augmented version of #132. With this PR both dev and release builds that do not use the owned-singleton stuff become reproducible. (I haven't really bothered to make owned-singleton reproducible since [lifo] is way more ergonomic than [alloc-singleton] and will eventually make its way into heapless). [lifo]: https://github.com/japaric/lifo [alloc-singleton]: https://crates.io/crates/alloc-singleton Thanks @hugwijst for doing the bulk of the work! closes #132 Co-authored-by: Hugo van der Wijst <hvanderwijst@tesla.com> Co-authored-by: Hugo van der Wijst <hugo@wij.st> Co-authored-by: Jorge Aparicio <jorge@japaric.io>
This commit is contained in:
commit
c91b14bcd4
9 changed files with 307 additions and 177 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@
|
||||||
/book/*/book
|
/book/*/book
|
||||||
/target
|
/target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
*.hex
|
||||||
|
|
|
@ -23,7 +23,10 @@ matrix:
|
||||||
rust: nightly
|
rust: nightly
|
||||||
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||||
|
|
||||||
before_install: set -e
|
before_install:
|
||||||
|
- set -e
|
||||||
|
- sudo apt-get update
|
||||||
|
- sudo apt-get install -y binutils-arm-none-eabi
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- bash ci/install.sh
|
- bash ci/install.sh
|
||||||
|
|
73
ci/script.sh
73
ci/script.sh
|
@ -1,8 +1,41 @@
|
||||||
set -euxo pipefail
|
set -euxo pipefail
|
||||||
|
|
||||||
|
arm_example() {
|
||||||
|
local COMMAND=$1
|
||||||
|
local EXAMPLE=$2
|
||||||
|
local BUILD_MODE=$3
|
||||||
|
local FEATURES=$4
|
||||||
|
local BUILD_NUM=$5
|
||||||
|
|
||||||
|
if [ $BUILD_MODE = "release" ]; then
|
||||||
|
local RELEASE_FLAG="--release"
|
||||||
|
else
|
||||||
|
local RELEASE_FLAG=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$FEATURES" ]; then
|
||||||
|
local FEATURES_FLAG="--features $FEATURES"
|
||||||
|
local FEATURES_STR=${FEATURES/,/_}_
|
||||||
|
else
|
||||||
|
local FEATURES_FLAG=""
|
||||||
|
local FEATURES_STR=""
|
||||||
|
fi
|
||||||
|
local CARGO_FLAGS="--example $EXAMPLE --target $TARGET $RELEASE_FLAG $FEATURES_FLAG"
|
||||||
|
|
||||||
|
if [ $COMMAND = "run" ]; then
|
||||||
|
cargo $COMMAND $CARGO_FLAGS | diff -u ci/expected/$EXAMPLE.run -
|
||||||
|
else
|
||||||
|
cargo $COMMAND $CARGO_FLAGS
|
||||||
|
fi
|
||||||
|
arm-none-eabi-objcopy -O ihex target/$TARGET/$BUILD_MODE/examples/$EXAMPLE ci/builds/${EXAMPLE}_${FEATURES_STR}${BUILD_MODE}_${BUILD_NUM}.hex
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
local T=$TARGET
|
local T=$TARGET
|
||||||
|
|
||||||
|
mkdir -p ci/builds
|
||||||
|
|
||||||
if [ $T = x86_64-unknown-linux-gnu ]; then
|
if [ $T = x86_64-unknown-linux-gnu ]; then
|
||||||
# compile-fail and compile-pass tests
|
# compile-fail and compile-pass tests
|
||||||
case $TRAVIS_RUST_VERSION in
|
case $TRAVIS_RUST_VERSION in
|
||||||
|
@ -82,19 +115,41 @@ main() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $ex != types ]; then
|
if [ $ex != types ]; then
|
||||||
cargo run --example $ex --target $T | \
|
arm_example "run" $ex "debug" "" "1"
|
||||||
diff -u ci/expected/$ex.run -
|
arm_example "run" $ex "release" "" "1"
|
||||||
|
|
||||||
cargo run --example $ex --target $T --release | \
|
|
||||||
diff -u ci/expected/$ex.run -
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $TARGET != thumbv6m-none-eabi ]; then
|
if [ $TARGET != thumbv6m-none-eabi ]; then
|
||||||
cargo run --features timer-queue --example $ex --target $T | \
|
arm_example "run" $ex "debug" "timer-queue" "1"
|
||||||
diff -u ci/expected/$ex.run -
|
arm_example "run" $ex "release" "timer-queue" "1"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
cargo run --features timer-queue --example $ex --target $T --release | \
|
cargo clean
|
||||||
diff -u ci/expected/$ex.run -
|
for ex in ${exs[@]}; do
|
||||||
|
if [ $ex = ramfunc ] && [ $T = thumbv6m-none-eabi ]; then
|
||||||
|
# LLD doesn't support this at the moment
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $ex = singleton ]; then
|
||||||
|
# singleton build is currently not reproducible due to
|
||||||
|
# https://github.com/japaric/owned-singleton/issues/2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $ex != types ]; then
|
||||||
|
arm_example "build" $ex "debug" "" "2"
|
||||||
|
cmp ci/builds/${ex}_debug_1.hex ci/builds/${ex}_debug_2.hex
|
||||||
|
arm_example "build" $ex "release" "" "2"
|
||||||
|
cmp ci/builds/${ex}_release_1.hex ci/builds/${ex}_release_2.hex
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $TARGET != thumbv6m-none-eabi ]; then
|
||||||
|
arm_example "build" $ex "debug" "timer-queue" "2"
|
||||||
|
cmp ci/builds/${ex}_timer-queue_debug_1.hex ci/builds/${ex}_timer-queue_debug_2.hex
|
||||||
|
arm_example "build" $ex "release" "timer-queue" "2"
|
||||||
|
cmp ci/builds/${ex}_timer-queue_release_1.hex ci/builds/${ex}_timer-queue_release_2.hex
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
cmp,
|
cmp,
|
||||||
collections::{HashMap, HashSet},
|
collections::{BTreeMap, HashMap, HashSet},
|
||||||
};
|
};
|
||||||
|
|
||||||
use syn::{Attribute, Ident, Type};
|
use syn::{Attribute, Ident, Type};
|
||||||
|
@ -65,7 +65,7 @@ pub struct Dispatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Priority -> Dispatcher
|
/// Priority -> Dispatcher
|
||||||
pub type Dispatchers = HashMap<u8, Dispatcher>;
|
pub type Dispatchers = BTreeMap<u8, Dispatcher>;
|
||||||
|
|
||||||
pub type Capacities = HashMap<Ident, u8>;
|
pub type Capacities = HashMap<Ident, u8>;
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,8 @@ pub fn app(app: &App) -> parse::Result<()> {
|
||||||
// Check that all late resources have been initialized in `#[init]` if `init` has signature
|
// Check that all late resources have been initialized in `#[init]` if `init` has signature
|
||||||
// `fn()`
|
// `fn()`
|
||||||
if !app.init.returns_late_resources {
|
if !app.init.returns_late_resources {
|
||||||
for res in app
|
for res in
|
||||||
.resources
|
app.resources
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(name, res)| if res.expr.is_none() { Some(name) } else { None })
|
.filter_map(|(name, res)| if res.expr.is_none() { Some(name) } else { None })
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::{BTreeMap, HashMap},
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,13 +19,13 @@ use crate::{
|
||||||
// NOTE to avoid polluting the user namespaces we map some identifiers to pseudo-hygienic names.
|
// NOTE to avoid polluting the user namespaces we map some identifiers to pseudo-hygienic names.
|
||||||
// In some instances we also use the pseudo-hygienic names for safety, for example the user should
|
// In some instances we also use the pseudo-hygienic names for safety, for example the user should
|
||||||
// not modify the priority field of resources.
|
// not modify the priority field of resources.
|
||||||
type Aliases = HashMap<Ident, Ident>;
|
type Aliases = BTreeMap<Ident, Ident>;
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
// Alias
|
// Alias
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
baseline: Ident,
|
baseline: Ident,
|
||||||
dispatchers: HashMap<u8, Dispatcher>,
|
dispatchers: BTreeMap<u8, Dispatcher>,
|
||||||
// Alias (`fn`)
|
// Alias (`fn`)
|
||||||
idle: Ident,
|
idle: Ident,
|
||||||
// Alias (`fn`)
|
// Alias (`fn`)
|
||||||
|
@ -41,9 +40,11 @@ struct Context {
|
||||||
schedule_enum: Ident,
|
schedule_enum: Ident,
|
||||||
// Task -> Alias (`fn`)
|
// Task -> Alias (`fn`)
|
||||||
schedule_fn: Aliases,
|
schedule_fn: Aliases,
|
||||||
tasks: HashMap<Ident, Task>,
|
tasks: BTreeMap<Ident, Task>,
|
||||||
// Alias (`struct` / `static mut`)
|
// Alias (`struct` / `static mut`)
|
||||||
timer_queue: Ident,
|
timer_queue: Ident,
|
||||||
|
// Generator of Ident names or suffixes
|
||||||
|
ident_gen: IdentGenerator,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Dispatcher {
|
struct Dispatcher {
|
||||||
|
@ -63,19 +64,22 @@ struct Task {
|
||||||
|
|
||||||
impl Default for Context {
|
impl Default for Context {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let mut ident_gen = IdentGenerator::new();
|
||||||
|
|
||||||
Context {
|
Context {
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
baseline: mk_ident(None),
|
baseline: ident_gen.mk_ident(None, false),
|
||||||
dispatchers: HashMap::new(),
|
dispatchers: BTreeMap::new(),
|
||||||
idle: mk_ident(Some("idle")),
|
idle: ident_gen.mk_ident(Some("idle"), false),
|
||||||
init: mk_ident(Some("init")),
|
init: ident_gen.mk_ident(Some("init"), false),
|
||||||
priority: mk_ident(None),
|
priority: ident_gen.mk_ident(None, false),
|
||||||
statics: Aliases::new(),
|
statics: Aliases::new(),
|
||||||
resources: HashMap::new(),
|
resources: HashMap::new(),
|
||||||
schedule_enum: mk_ident(None),
|
schedule_enum: ident_gen.mk_ident(None, false),
|
||||||
schedule_fn: Aliases::new(),
|
schedule_fn: Aliases::new(),
|
||||||
tasks: HashMap::new(),
|
tasks: BTreeMap::new(),
|
||||||
timer_queue: mk_ident(None),
|
timer_queue: ident_gen.mk_ident(None, false),
|
||||||
|
ident_gen,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,13 +168,13 @@ pub fn app(app: &App, analysis: &Analysis) -> TokenStream {
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let timer_queue = timer_queue(&ctxt, app, analysis);
|
let timer_queue = timer_queue(&mut ctxt, app, analysis);
|
||||||
|
|
||||||
let pre_init = pre_init(&ctxt, &app, analysis);
|
let pre_init = pre_init(&ctxt, &app, analysis);
|
||||||
|
|
||||||
let assertions = assertions(app, analysis);
|
let assertions = assertions(app, analysis);
|
||||||
|
|
||||||
let main = mk_ident(None);
|
let main = ctxt.ident_gen.mk_ident(None, false);
|
||||||
quote!(
|
quote!(
|
||||||
#resources
|
#resources
|
||||||
|
|
||||||
|
@ -236,7 +240,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2:
|
||||||
pub static #mut_ #name: #ty = #expr;
|
pub static #mut_ #name: #ty = #expr;
|
||||||
));
|
));
|
||||||
|
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None, true); // XXX is randomness required?
|
||||||
if let Some(Ownership::Shared { ceiling }) = analysis.ownerships.get(name) {
|
if let Some(Ownership::Shared { ceiling }) = analysis.ownerships.get(name) {
|
||||||
items.push(mk_resource(
|
items.push(mk_resource(
|
||||||
ctxt,
|
ctxt,
|
||||||
|
@ -252,7 +256,7 @@ fn resources(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2:
|
||||||
|
|
||||||
ctxt.statics.insert(name.clone(), alias);
|
ctxt.statics.insert(name.clone(), alias);
|
||||||
} else {
|
} else {
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
let symbol = format!("{}::{}", name, alias);
|
let symbol = format!("{}::{}", name, alias);
|
||||||
|
|
||||||
items.push(
|
items.push(
|
||||||
|
@ -360,7 +364,7 @@ fn init(ctxt: &mut Context, app: &App, analysis: &Analysis) -> (proc_macro2::Tok
|
||||||
|
|
||||||
let (late_resources, late_resources_ident, ret) = if app.init.returns_late_resources {
|
let (late_resources, late_resources_ident, ret) = if app.init.returns_late_resources {
|
||||||
// create `LateResources` struct in the root of the crate
|
// create `LateResources` struct in the root of the crate
|
||||||
let ident = mk_ident(None);
|
let ident = ctxt.ident_gen.mk_ident(None, false);
|
||||||
|
|
||||||
let fields = app
|
let fields = app
|
||||||
.resources
|
.resources
|
||||||
|
@ -405,7 +409,7 @@ fn init(ctxt: &mut Context, app: &App, analysis: &Analysis) -> (proc_macro2::Tok
|
||||||
let baseline = &ctxt.baseline;
|
let baseline = &ctxt.baseline;
|
||||||
let baseline_let = match () {
|
let baseline_let = match () {
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
() => quote!(let #baseline = rtfm::Instant::artificial(0);),
|
() => quote!(let ref #baseline = rtfm::Instant::artificial(0);),
|
||||||
|
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
|
@ -415,7 +419,7 @@ fn init(ctxt: &mut Context, app: &App, analysis: &Analysis) -> (proc_macro2::Tok
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
() => quote!(
|
() => quote!(
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let start = #baseline;
|
let start = *#baseline;
|
||||||
),
|
),
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
|
@ -430,8 +434,11 @@ fn init(ctxt: &mut Context, app: &App, analysis: &Analysis) -> (proc_macro2::Tok
|
||||||
|
|
||||||
#module
|
#module
|
||||||
|
|
||||||
|
// unsafe trampoline to deter end-users from calling this non-reentrant function
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#unsafety fn #init(mut core: rtfm::Peripherals) #ret {
|
unsafe fn #init(core: rtfm::Peripherals) #ret {
|
||||||
|
#[inline(always)]
|
||||||
|
#unsafety fn init(mut core: rtfm::Peripherals) #ret {
|
||||||
#(#locals)*
|
#(#locals)*
|
||||||
|
|
||||||
#baseline_let
|
#baseline_let
|
||||||
|
@ -446,6 +453,9 @@ fn init(ctxt: &mut Context, app: &App, analysis: &Analysis) -> (proc_macro2::Tok
|
||||||
|
|
||||||
#(#assigns)*
|
#(#assigns)*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init(core)
|
||||||
|
}
|
||||||
),
|
),
|
||||||
has_late_resources,
|
has_late_resources,
|
||||||
)
|
)
|
||||||
|
@ -563,7 +573,7 @@ fn module(
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Schedule<'a> {
|
pub struct Schedule<'a> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub #priority: &'a core::cell::Cell<u8>,
|
pub #priority: &'a rtfm::export::Priority,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -582,7 +592,7 @@ fn module(
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Spawn<'a> {
|
pub struct Spawn<'a> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub #priority: &'a core::cell::Cell<u8>,
|
pub #priority: &'a rtfm::export::Priority,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
|
@ -591,8 +601,10 @@ fn module(
|
||||||
() => {
|
() => {
|
||||||
let baseline = &ctxt.baseline;
|
let baseline = &ctxt.baseline;
|
||||||
quote!(
|
quote!(
|
||||||
|
// NOTE this field is visible so we use a shared reference to make it
|
||||||
|
// immutable
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub #baseline: rtfm::Instant,
|
pub #baseline: &'a rtfm::Instant,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
|
@ -605,7 +617,7 @@ fn module(
|
||||||
pub struct Spawn<'a> {
|
pub struct Spawn<'a> {
|
||||||
#baseline_field
|
#baseline_field
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub #priority: &'a core::cell::Cell<u8>,
|
pub #priority: &'a rtfm::export::Priority,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -687,7 +699,7 @@ fn prelude(
|
||||||
let mut exprs = vec![];
|
let mut exprs = vec![];
|
||||||
|
|
||||||
// NOTE This field is just to avoid unused type parameter errors around `'a`
|
// NOTE This field is just to avoid unused type parameter errors around `'a`
|
||||||
defs.push(quote!(#[allow(dead_code)] #priority: &'a core::cell::Cell<u8>));
|
defs.push(quote!(#[allow(dead_code)] pub #priority: &'a rtfm::export::Priority));
|
||||||
exprs.push(parse_quote!(#priority));
|
exprs.push(parse_quote!(#priority));
|
||||||
|
|
||||||
let mut may_call_lock = false;
|
let mut may_call_lock = false;
|
||||||
|
@ -826,7 +838,8 @@ fn prelude(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
pub #name: &'a #mut_ #name
|
pub #name: &'a #mut_ #name
|
||||||
));
|
));
|
||||||
let alias = mk_ident(None);
|
// XXX is randomness required?
|
||||||
|
let alias = ctxt.ident_gen.mk_ident(None, true);
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
let #mut_ #alias = unsafe {
|
let #mut_ #alias = unsafe {
|
||||||
|
@ -843,7 +856,8 @@ fn prelude(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
pub #name: rtfm::Exclusive<'a, #name>
|
pub #name: rtfm::Exclusive<'a, #name>
|
||||||
));
|
));
|
||||||
let alias = mk_ident(None);
|
// XXX is randomness required?
|
||||||
|
let alias = ctxt.ident_gen.mk_ident(None, true);
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
let #mut_ #alias = unsafe {
|
let #mut_ #alias = unsafe {
|
||||||
|
@ -910,7 +924,7 @@ fn prelude(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
let unsafety = if needs_unsafe {
|
let unsafety = if needs_unsafe {
|
||||||
Some(quote!(unsafe))
|
Some(quote!(unsafe))
|
||||||
} else {
|
} else {
|
||||||
|
@ -971,7 +985,8 @@ fn prelude(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxt.schedule_fn.insert(task.clone(), mk_ident(None));
|
ctxt.schedule_fn
|
||||||
|
.insert(task.clone(), ctxt.ident_gen.mk_ident(None, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
|
@ -987,7 +1002,7 @@ fn prelude(
|
||||||
quote!()
|
quote!()
|
||||||
} else {
|
} else {
|
||||||
quote!(
|
quote!(
|
||||||
let ref #priority = core::cell::Cell::new(#logical_prio);
|
let ref #priority = unsafe { rtfm::export::Priority::new(#logical_prio) };
|
||||||
|
|
||||||
#(#items)*
|
#(#items)*
|
||||||
)
|
)
|
||||||
|
@ -1031,14 +1046,20 @@ fn idle(
|
||||||
quote!(
|
quote!(
|
||||||
#module
|
#module
|
||||||
|
|
||||||
|
// unsafe trampoline to deter end-users from calling this non-reentrant function
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#unsafety fn #idle() -> ! {
|
unsafe fn #idle() -> ! {
|
||||||
|
#[inline(always)]
|
||||||
|
#unsafety fn idle() -> ! {
|
||||||
#(#locals)*
|
#(#locals)*
|
||||||
|
|
||||||
#prelude
|
#prelude
|
||||||
|
|
||||||
#(#stmts)*
|
#(#stmts)*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
idle()
|
||||||
|
}
|
||||||
),
|
),
|
||||||
quote!(#idle()),
|
quote!(#idle()),
|
||||||
)
|
)
|
||||||
|
@ -1083,7 +1104,7 @@ fn exceptions(ctxt: &mut Context, app: &App, analysis: &Analysis) -> Vec<proc_ma
|
||||||
let baseline = &ctxt.baseline;
|
let baseline = &ctxt.baseline;
|
||||||
let baseline_let = match () {
|
let baseline_let = match () {
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
() => quote!(let #baseline = rtfm::Instant::now();),
|
() => quote!(let ref #baseline = rtfm::Instant::now();),
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
};
|
};
|
||||||
|
@ -1092,7 +1113,7 @@ fn exceptions(ctxt: &mut Context, app: &App, analysis: &Analysis) -> Vec<proc_ma
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
() => quote!(
|
() => quote!(
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let start = #baseline;
|
let start = *#baseline;
|
||||||
),
|
),
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
|
@ -1100,15 +1121,17 @@ fn exceptions(ctxt: &mut Context, app: &App, analysis: &Analysis) -> Vec<proc_ma
|
||||||
|
|
||||||
let locals = mk_locals(&exception.statics, false);
|
let locals = mk_locals(&exception.statics, false);
|
||||||
let symbol = ident.to_string();
|
let symbol = ident.to_string();
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
let unsafety = &exception.unsafety;
|
let unsafety = &exception.unsafety;
|
||||||
quote!(
|
quote!(
|
||||||
#module
|
#module
|
||||||
|
|
||||||
#[doc(hidden)]
|
// unsafe trampoline to deter end-users from calling this non-reentrant function
|
||||||
#[export_name = #symbol]
|
#[export_name = #symbol]
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#unsafety fn #alias() {
|
unsafe fn #alias() {
|
||||||
|
#[inline(always)]
|
||||||
|
#unsafety fn exception() {
|
||||||
#(#locals)*
|
#(#locals)*
|
||||||
|
|
||||||
#baseline_let
|
#baseline_let
|
||||||
|
@ -1121,6 +1144,9 @@ fn exceptions(ctxt: &mut Context, app: &App, analysis: &Analysis) -> Vec<proc_ma
|
||||||
#(#stmts)*
|
#(#stmts)*
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exception()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -1163,7 +1189,7 @@ fn interrupts(
|
||||||
let baseline = &ctxt.baseline;
|
let baseline = &ctxt.baseline;
|
||||||
let baseline_let = match () {
|
let baseline_let = match () {
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
() => quote!(let #baseline = rtfm::Instant::now();),
|
() => quote!(let ref #baseline = rtfm::Instant::now();),
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
};
|
};
|
||||||
|
@ -1172,20 +1198,23 @@ fn interrupts(
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
() => quote!(
|
() => quote!(
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let start = #baseline;
|
let start = *#baseline;
|
||||||
),
|
),
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let locals = mk_locals(&interrupt.statics, false);
|
let locals = mk_locals(&interrupt.statics, false);
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
let symbol = ident.to_string();
|
let symbol = ident.to_string();
|
||||||
let unsafety = &interrupt.unsafety;
|
let unsafety = &interrupt.unsafety;
|
||||||
scoped.push(quote!(
|
scoped.push(quote!(
|
||||||
|
// unsafe trampoline to deter end-users from calling this non-reentrant function
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#[export_name = #symbol]
|
#[export_name = #symbol]
|
||||||
#unsafety fn #alias() {
|
unsafe fn #alias() {
|
||||||
|
#[inline(always)]
|
||||||
|
#unsafety fn interrupt() {
|
||||||
// check that this interrupt exists
|
// check that this interrupt exists
|
||||||
let _ = #device::interrupt::#ident;
|
let _ = #device::interrupt::#ident;
|
||||||
|
|
||||||
|
@ -1201,6 +1230,9 @@ fn interrupts(
|
||||||
#(#stmts)*
|
#(#stmts)*
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interrupt()
|
||||||
|
}
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1213,10 +1245,10 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
// first pass to generate buffers (statics and resources) and spawn aliases
|
// first pass to generate buffers (statics and resources) and spawn aliases
|
||||||
for (name, task) in &app.tasks {
|
for (name, task) in &app.tasks {
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
let scheduleds_alias = mk_ident(None);
|
let scheduleds_alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
let free_alias = mk_ident(None);
|
let free_alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
let inputs_alias = mk_ident(None);
|
let inputs_alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
let task_alias = mk_ident(Some(&name.to_string()));
|
let task_alias = ctxt.ident_gen.mk_ident(Some(&name.to_string()), false);
|
||||||
|
|
||||||
let inputs = &task.inputs;
|
let inputs = &task.inputs;
|
||||||
|
|
||||||
|
@ -1277,7 +1309,7 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
alias: task_alias,
|
alias: task_alias,
|
||||||
free_queue: free_alias,
|
free_queue: free_alias,
|
||||||
inputs: inputs_alias,
|
inputs: inputs_alias,
|
||||||
spawn_fn: mk_ident(None),
|
spawn_fn: ctxt.ident_gen.mk_ident(None, false),
|
||||||
|
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
scheduleds: scheduleds_alias,
|
scheduleds: scheduleds_alias,
|
||||||
|
@ -1296,7 +1328,7 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
() => {
|
() => {
|
||||||
let baseline = &ctxt.baseline;
|
let baseline = &ctxt.baseline;
|
||||||
quote!(let scheduled = #baseline;)
|
quote!(let scheduled = *#baseline;)
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
() => quote!(),
|
() => quote!(),
|
||||||
|
@ -1325,19 +1357,23 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
let attrs = &task.attrs;
|
let attrs = &task.attrs;
|
||||||
let cfgs = &task.cfgs;
|
let cfgs = &task.cfgs;
|
||||||
let task_alias = &ctxt.tasks[name].alias;
|
let task_alias = &ctxt.tasks[name].alias;
|
||||||
let baseline_arg = match () {
|
let (baseline, baseline_arg) = match () {
|
||||||
#[cfg(feature = "timer-queue")]
|
#[cfg(feature = "timer-queue")]
|
||||||
() => {
|
() => {
|
||||||
let baseline = &ctxt.baseline;
|
let baseline = &ctxt.baseline;
|
||||||
quote!(#baseline: rtfm::Instant,)
|
(quote!(#baseline,), quote!(#baseline: &rtfm::Instant,))
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
() => quote!(),
|
() => (quote!(), quote!()),
|
||||||
};
|
};
|
||||||
|
let pats = tuple_pat(inputs);
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
|
// unsafe trampoline to deter end-users from calling this non-reentrant function
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
#unsafety fn #task_alias(#baseline_arg #(#inputs,)*) {
|
unsafe fn #task_alias(#baseline_arg #(#inputs,)*) {
|
||||||
|
#[inline(always)]
|
||||||
|
#unsafety fn task(#baseline_arg #(#inputs,)*) {
|
||||||
#(#locals)*
|
#(#locals)*
|
||||||
|
|
||||||
#prelude
|
#prelude
|
||||||
|
@ -1346,6 +1382,9 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
|
||||||
|
|
||||||
#(#stmts)*
|
#(#stmts)*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task(#baseline #pats)
|
||||||
|
}
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1362,8 +1401,8 @@ fn dispatchers(
|
||||||
|
|
||||||
let device = &app.args.device;
|
let device = &app.args.device;
|
||||||
for (level, dispatcher) in &analysis.dispatchers {
|
for (level, dispatcher) in &analysis.dispatchers {
|
||||||
let ready_alias = mk_ident(None);
|
let ready_alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
let enum_alias = mk_ident(None);
|
let enum_alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
let capacity = mk_typenum_capacity(dispatcher.capacity, true);
|
let capacity = mk_typenum_capacity(dispatcher.capacity, true);
|
||||||
|
|
||||||
let variants = dispatcher
|
let variants = dispatcher
|
||||||
|
@ -1427,7 +1466,7 @@ fn dispatchers(
|
||||||
let baseline =
|
let baseline =
|
||||||
ptr::read(#scheduleds.get_ref().get_unchecked(usize::from(index)));
|
ptr::read(#scheduleds.get_ref().get_unchecked(usize::from(index)));
|
||||||
);
|
);
|
||||||
call = quote!(#alias(baseline, #pats));
|
call = quote!(#alias(&baseline, #pats));
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
() => {
|
() => {
|
||||||
|
@ -1452,7 +1491,7 @@ fn dispatchers(
|
||||||
let attrs = &dispatcher.attrs;
|
let attrs = &dispatcher.attrs;
|
||||||
let interrupt = &dispatcher.interrupt;
|
let interrupt = &dispatcher.interrupt;
|
||||||
let symbol = interrupt.to_string();
|
let symbol = interrupt.to_string();
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
dispatchers.push(quote!(
|
dispatchers.push(quote!(
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#[export_name = #symbol]
|
#[export_name = #symbol]
|
||||||
|
@ -1534,7 +1573,7 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
unsafe fn #alias(
|
unsafe fn #alias(
|
||||||
#baseline_arg
|
#baseline_arg
|
||||||
#priority: &core::cell::Cell<u8>,
|
#priority: &rtfm::export::Priority,
|
||||||
#(#args,)*
|
#(#args,)*
|
||||||
) -> Result<(), #ty> {
|
) -> Result<(), #ty> {
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
@ -1583,7 +1622,7 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
|
||||||
if is_idle {
|
if is_idle {
|
||||||
quote!(rtfm::Instant::now(),)
|
quote!(rtfm::Instant::now(),)
|
||||||
} else {
|
} else {
|
||||||
quote!(self.#baseline,)
|
quote!(*self.#baseline,)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "timer-queue"))]
|
#[cfg(not(feature = "timer-queue"))]
|
||||||
|
@ -1632,7 +1671,7 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
unsafe fn #alias(
|
unsafe fn #alias(
|
||||||
#priority: &core::cell::Cell<u8>,
|
#priority: &rtfm::export::Priority,
|
||||||
instant: rtfm::Instant,
|
instant: rtfm::Instant,
|
||||||
#(#args,)*
|
#(#args,)*
|
||||||
) -> Result<(), #ty> {
|
) -> Result<(), #ty> {
|
||||||
|
@ -1703,7 +1742,7 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream {
|
||||||
quote!(#(#items)*)
|
quote!(#(#items)*)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timer_queue(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenStream {
|
fn timer_queue(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenStream {
|
||||||
let tasks = &analysis.timer_queue.tasks;
|
let tasks = &analysis.timer_queue.tasks;
|
||||||
|
|
||||||
if tasks.is_empty() {
|
if tasks.is_empty() {
|
||||||
|
@ -1778,14 +1817,14 @@ fn timer_queue(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::T
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let logical_prio = analysis.timer_queue.priority;
|
let logical_prio = analysis.timer_queue.priority;
|
||||||
let alias = mk_ident(None);
|
let alias = ctxt.ident_gen.mk_ident(None, false);
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#[export_name = "SysTick"]
|
#[export_name = "SysTick"]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
unsafe fn #alias() {
|
unsafe fn #alias() {
|
||||||
use rtfm::Mutex;
|
use rtfm::Mutex;
|
||||||
|
|
||||||
let ref #priority = core::cell::Cell::new(#logical_prio);
|
let ref #priority = rtfm::export::Priority::new(#logical_prio);
|
||||||
|
|
||||||
rtfm::export::run(|| {
|
rtfm::export::run(|| {
|
||||||
rtfm::export::sys_tick(#tq { #priority }, |task, index| {
|
rtfm::export::sys_tick(#tq { #priority }, |task, index| {
|
||||||
|
@ -1929,7 +1968,7 @@ fn mk_resource(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
pub struct #struct_<'a> {
|
pub struct #struct_<'a> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub #priority: &'a core::cell::Cell<u8>,
|
pub #priority: &'a rtfm::export::Priority,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -1938,7 +1977,7 @@ fn mk_resource(
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
struct #struct_<'a> {
|
struct #struct_<'a> {
|
||||||
#priority: &'a core::cell::Cell<u8>,
|
#priority: &'a rtfm::export::Priority,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -1989,15 +2028,18 @@ fn mk_typenum_capacity(capacity: u8, power_of_two: bool) -> proc_macro2::TokenSt
|
||||||
quote!(rtfm::export::consts::#ident)
|
quote!(rtfm::export::consts::#ident)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_ident(name: Option<&str>) -> Ident {
|
struct IdentGenerator {
|
||||||
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
call_count: u32,
|
||||||
|
rng: rand::rngs::SmallRng,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdentGenerator {
|
||||||
|
fn new() -> IdentGenerator {
|
||||||
let elapsed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
let elapsed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||||
|
|
||||||
let secs = elapsed.as_secs();
|
let secs = elapsed.as_secs();
|
||||||
let nanos = elapsed.subsec_nanos();
|
let nanos = elapsed.subsec_nanos();
|
||||||
|
|
||||||
let count = CALL_COUNT.fetch_add(1, Ordering::SeqCst) as u32;
|
|
||||||
let mut seed: [u8; 16] = [0; 16];
|
let mut seed: [u8; 16] = [0; 16];
|
||||||
|
|
||||||
for (i, v) in seed.iter_mut().take(8).enumerate() {
|
for (i, v) in seed.iter_mut().take(8).enumerate() {
|
||||||
|
@ -2008,33 +2050,39 @@ fn mk_ident(name: Option<&str>) -> Ident {
|
||||||
*v = ((nanos >> (i * 8)) & 0xFF) as u8
|
*v = ((nanos >> (i * 8)) & 0xFF) as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, v) in seed.iter_mut().skip(12).enumerate() {
|
let rng = rand::rngs::SmallRng::from_seed(seed);
|
||||||
*v = ((count >> (i * 8)) & 0xFF) as u8
|
|
||||||
|
IdentGenerator { call_count: 0, rng }
|
||||||
}
|
}
|
||||||
|
|
||||||
let n;
|
fn mk_ident(&mut self, name: Option<&str>, random: bool) -> Ident {
|
||||||
let mut s = if let Some(name) = name {
|
let s = if let Some(name) = name {
|
||||||
n = 4;
|
|
||||||
format!("{}_", name)
|
format!("{}_", name)
|
||||||
} else {
|
} else {
|
||||||
n = 16;
|
"__rtfm_internal_".to_string()
|
||||||
String::new()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut rng = rand::rngs::SmallRng::from_seed(seed);
|
let mut s = format!("{}{}", s, self.call_count);
|
||||||
for i in 0..n {
|
self.call_count += 1;
|
||||||
if i == 0 || rng.gen() {
|
|
||||||
s.push(('a' as u8 + rng.gen::<u8>() % 25) as char)
|
if random {
|
||||||
|
s.push('_');
|
||||||
|
|
||||||
|
for i in 0..4 {
|
||||||
|
if i == 0 || self.rng.gen() {
|
||||||
|
s.push(('a' as u8 + self.rng.gen::<u8>() % 25) as char)
|
||||||
} else {
|
} else {
|
||||||
s.push(('0' as u8 + rng.gen::<u8>() % 10) as char)
|
s.push(('0' as u8 + self.rng.gen::<u8>() % 10) as char)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ident::new(&s, Span::call_site())
|
Ident::new(&s, Span::call_site())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// `once = true` means that these locals will be called from a function that will run *once*
|
// `once = true` means that these locals will be called from a function that will run *once*
|
||||||
fn mk_locals(locals: &HashMap<Ident, Static>, once: bool) -> proc_macro2::TokenStream {
|
fn mk_locals(locals: &BTreeMap<Ident, Static>, once: bool) -> proc_macro2::TokenStream {
|
||||||
let lt = if once { Some(quote!('static)) } else { None };
|
let lt = if once { Some(quote!('static)) } else { None };
|
||||||
|
|
||||||
let locals = locals
|
let locals = locals
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
iter, u8,
|
iter, u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -120,10 +120,10 @@ impl App {
|
||||||
pub fn parse(items: Vec<Item>, args: AppArgs) -> parse::Result<Self> {
|
pub fn parse(items: Vec<Item>, args: AppArgs) -> parse::Result<Self> {
|
||||||
let mut idle = None;
|
let mut idle = None;
|
||||||
let mut init = None;
|
let mut init = None;
|
||||||
let mut exceptions = HashMap::new();
|
let mut exceptions = BTreeMap::new();
|
||||||
let mut interrupts = HashMap::new();
|
let mut interrupts = BTreeMap::new();
|
||||||
let mut resources = HashMap::new();
|
let mut resources = BTreeMap::new();
|
||||||
let mut tasks = HashMap::new();
|
let mut tasks = BTreeMap::new();
|
||||||
let mut free_interrupts = None;
|
let mut free_interrupts = None;
|
||||||
|
|
||||||
for item in items {
|
for item in items {
|
||||||
|
@ -418,25 +418,25 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Idents = HashSet<Ident>;
|
pub type Idents = BTreeSet<Ident>;
|
||||||
|
|
||||||
pub type Exceptions = HashMap<Ident, Exception>;
|
pub type Exceptions = BTreeMap<Ident, Exception>;
|
||||||
|
|
||||||
pub type Interrupts = HashMap<Ident, Interrupt>;
|
pub type Interrupts = BTreeMap<Ident, Interrupt>;
|
||||||
|
|
||||||
pub type Resources = HashMap<Ident, Resource>;
|
pub type Resources = BTreeMap<Ident, Resource>;
|
||||||
|
|
||||||
pub type Statics = Vec<ItemStatic>;
|
pub type Statics = Vec<ItemStatic>;
|
||||||
|
|
||||||
pub type Tasks = HashMap<Ident, Task>;
|
pub type Tasks = BTreeMap<Ident, Task>;
|
||||||
|
|
||||||
pub type FreeInterrupts = HashMap<Ident, FreeInterrupt>;
|
pub type FreeInterrupts = BTreeMap<Ident, FreeInterrupt>;
|
||||||
|
|
||||||
pub struct Idle {
|
pub struct Idle {
|
||||||
pub args: IdleArgs,
|
pub args: IdleArgs,
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub unsafety: Option<Token![unsafe]>,
|
pub unsafety: Option<Token![unsafe]>,
|
||||||
pub statics: HashMap<Ident, Static>,
|
pub statics: BTreeMap<Ident, Static>,
|
||||||
pub stmts: Vec<Stmt>,
|
pub stmts: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,7 +607,7 @@ pub struct Init {
|
||||||
pub args: InitArgs,
|
pub args: InitArgs,
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub unsafety: Option<Token![unsafe]>,
|
pub unsafety: Option<Token![unsafe]>,
|
||||||
pub statics: HashMap<Ident, Static>,
|
pub statics: BTreeMap<Ident, Static>,
|
||||||
pub stmts: Vec<Stmt>,
|
pub stmts: Vec<Stmt>,
|
||||||
// TODO remove in v0.5.x
|
// TODO remove in v0.5.x
|
||||||
pub assigns: Vec<Assign>,
|
pub assigns: Vec<Assign>,
|
||||||
|
@ -703,7 +703,7 @@ pub struct Exception {
|
||||||
pub args: ExceptionArgs,
|
pub args: ExceptionArgs,
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub unsafety: Option<Token![unsafe]>,
|
pub unsafety: Option<Token![unsafe]>,
|
||||||
pub statics: HashMap<Ident, Static>,
|
pub statics: BTreeMap<Ident, Static>,
|
||||||
pub stmts: Vec<Stmt>,
|
pub stmts: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,7 +791,7 @@ pub struct Interrupt {
|
||||||
pub args: InterruptArgs,
|
pub args: InterruptArgs,
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub unsafety: Option<Token![unsafe]>,
|
pub unsafety: Option<Token![unsafe]>,
|
||||||
pub statics: HashMap<Ident, Static>,
|
pub statics: BTreeMap<Ident, Static>,
|
||||||
pub stmts: Vec<Stmt>,
|
pub stmts: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1070,8 +1070,8 @@ pub struct Static {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Static {
|
impl Static {
|
||||||
fn parse(items: Vec<ItemStatic>) -> parse::Result<HashMap<Ident, Static>> {
|
fn parse(items: Vec<ItemStatic>) -> parse::Result<BTreeMap<Ident, Static>> {
|
||||||
let mut statics = HashMap::new();
|
let mut statics = BTreeMap::new();
|
||||||
|
|
||||||
for item in items {
|
for item in items {
|
||||||
if statics.contains_key(&item.ident) {
|
if statics.contains_key(&item.ident) {
|
||||||
|
@ -1104,7 +1104,7 @@ pub struct Task {
|
||||||
pub attrs: Vec<Attribute>,
|
pub attrs: Vec<Attribute>,
|
||||||
pub unsafety: Option<Token![unsafe]>,
|
pub unsafety: Option<Token![unsafe]>,
|
||||||
pub inputs: Vec<ArgCaptured>,
|
pub inputs: Vec<ArgCaptured>,
|
||||||
pub statics: HashMap<Ident, Static>,
|
pub statics: BTreeMap<Ident, Static>,
|
||||||
pub stmts: Vec<Stmt>,
|
pub stmts: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,31 @@ where
|
||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Newtype over `Cell` that forbids mutation through a shared reference
|
||||||
|
pub struct Priority {
|
||||||
|
inner: Cell<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Priority {
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn new(value: u8) -> Self {
|
||||||
|
Priority {
|
||||||
|
inner: Cell::new(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// these two methods are used by claim (see below) but can't be used from the RTFM application
|
||||||
|
#[inline(always)]
|
||||||
|
fn set(&self, value: u8) {
|
||||||
|
self.inner.set(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn get(&self) -> u8 {
|
||||||
|
self.inner.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(MaybeUninit) Until core::mem::MaybeUninit is stabilized we use our own (inefficient)
|
// TODO(MaybeUninit) Until core::mem::MaybeUninit is stabilized we use our own (inefficient)
|
||||||
// implementation
|
// implementation
|
||||||
pub struct MaybeUninit<T> {
|
pub struct MaybeUninit<T> {
|
||||||
|
@ -102,7 +127,7 @@ where
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn claim<T, R, F>(
|
pub unsafe fn claim<T, R, F>(
|
||||||
ptr: *mut T,
|
ptr: *mut T,
|
||||||
priority: &Cell<u8>,
|
priority: &Priority,
|
||||||
ceiling: u8,
|
ceiling: u8,
|
||||||
nvic_prio_bits: u8,
|
nvic_prio_bits: u8,
|
||||||
f: F,
|
f: F,
|
||||||
|
@ -135,7 +160,7 @@ where
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn claim<T, R, F>(
|
pub unsafe fn claim<T, R, F>(
|
||||||
ptr: *mut T,
|
ptr: *mut T,
|
||||||
priority: &Cell<u8>,
|
priority: &Priority,
|
||||||
ceiling: u8,
|
ceiling: u8,
|
||||||
_nvic_prio_bits: u8,
|
_nvic_prio_bits: u8,
|
||||||
f: F,
|
f: F,
|
||||||
|
|
|
@ -38,8 +38,7 @@ fn cfail() {
|
||||||
let f = f.unwrap().path();
|
let f = f.unwrap().path();
|
||||||
let name = f.file_stem().unwrap().to_str().unwrap();
|
let name = f.file_stem().unwrap().to_str().unwrap();
|
||||||
|
|
||||||
assert!(
|
assert!(Command::new("rustc")
|
||||||
Command::new("rustc")
|
|
||||||
.args(s.split_whitespace())
|
.args(s.split_whitespace())
|
||||||
.arg(f.display().to_string())
|
.arg(f.display().to_string())
|
||||||
.arg("-o")
|
.arg("-o")
|
||||||
|
@ -48,8 +47,7 @@ fn cfail() {
|
||||||
.arg("linker=true")
|
.arg("linker=true")
|
||||||
.status()
|
.status()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.success()
|
.success());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config.target_rustcflags = Some(s);
|
config.target_rustcflags = Some(s);
|
||||||
|
|
Loading…
Reference in a new issue