Skip to content

Commit

Permalink
Merge #589
Browse files Browse the repository at this point in the history
589: Fine grained concurrency on thumbv6m (no BASEPRI). r=korken89 a=perlindgren

This is an experimental implementation of SRP based scheduling on the M0/M0+ (thumbv6m) architecture. 

The aim is a (sub)-zero abstraction to the resource protection (locking mechanism).

Please try, but not merge yet, since its an early POC. 

Co-authored-by: Per Lindgren <per.lindgren@ltu.se>
  • Loading branch information
bors[bot] and perlindgren committed Mar 4, 2022
2 parents 790b074 + f86dab5 commit a765f3f
Show file tree
Hide file tree
Showing 9 changed files with 434 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
- Rework branch structure, release/vVERSION
- Cargo clippy in CI
- Use rust-cache Github Action
- Support for NVIC based SPR based scheduling for armv6m.
- CI changelog entry enforcer
- `examples/periodic-at.rs`, an example of a periodic timer without accumulated drift.
- `examples/periodic-at2.rs`, an example of a periodic process with two tasks, with offset timing.
Expand Down
47 changes: 47 additions & 0 deletions ci/expected/complex.run
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
init
idle p0 started
t2 p4 called 1 time
enter lock s4 0
t3 p4 exit
idle enter lock s3 0
idle pend t0
idle pend t1
idle pend t2
t2 p4 called 2 times
enter lock s4 1
t3 p4 exit
idle still in lock s3 0
t1 p3 called 1 time
t1 enter lock s4 2
t1 pend t0
t1 pend t2
t1 still in lock s4 2
t2 p4 called 3 times
enter lock s4 2
t3 p4 exit
t1 p3 exit
t0 p2 called 1 time
t0 p2 exit

back in idle
enter lock s2 0
idle pend t0
idle pend t1
t1 p3 called 2 times
t1 enter lock s4 3
t1 pend t0
t1 pend t2
t1 still in lock s4 3
t2 p4 called 4 times
enter lock s4 3
t3 p4 exit
t1 p3 exit
idle pend t2
t2 p4 called 5 times
enter lock s4 4
t3 p4 exit
idle still in lock s2 0
t0 p2 called 2 times
t0 p2 exit

idle exit
132 changes: 132 additions & 0 deletions examples/complex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//! examples/complex.rs

#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]

use panic_semihosting as _;

#[rtic::app(device = lm3s6965)]
mod app {

use cortex_m_semihosting::{debug, hprintln};
use lm3s6965::Interrupt;

#[shared]
struct Shared {
s2: u32, // shared with ceiling 2
s3: u32, // shared with ceiling 3
s4: u32, // shared with ceiling 4
}

#[local]
struct Local {}

#[init]
fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {
hprintln!("init").unwrap();

(
Shared {
s2: 0,
s3: 0,
s4: 0,
},
Local {},
init::Monotonics(),
)
}

#[idle(shared = [s2, s3])]
fn idle(mut cx: idle::Context) -> ! {
hprintln!("idle p0 started").ok();
rtic::pend(Interrupt::GPIOC);
cx.shared.s3.lock(|s| {
hprintln!("idle enter lock s3 {}", s).ok();
hprintln!("idle pend t0").ok();
rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 3
hprintln!("idle pend t1").ok();
rtic::pend(Interrupt::GPIOB); // t1 p3, with shared ceiling 3
hprintln!("idle pend t2").ok();
rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing
hprintln!("idle still in lock s3 {}", s).ok();
});
hprintln!("\nback in idle").ok();

cx.shared.s2.lock(|s| {
hprintln!("enter lock s2 {}", s).ok();
hprintln!("idle pend t0").ok();
rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 2
hprintln!("idle pend t1").ok();
rtic::pend(Interrupt::GPIOB); // t1 p3, no sharing
hprintln!("idle pend t2").ok();
rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing
hprintln!("idle still in lock s2 {}", s).ok();
});
hprintln!("\nidle exit").ok();

debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator

loop {
cortex_m::asm::nop();
}
}

#[task(binds = GPIOA, priority = 2, local = [times: u32 = 0], shared = [s2, s3])]
fn t0(cx: t0::Context) {
// Safe access to local `static mut` variable
*cx.local.times += 1;

hprintln!(
"t0 p2 called {} time{}",
*cx.local.times,
if *cx.local.times > 1 { "s" } else { "" }
)
.ok();
hprintln!("t0 p2 exit").ok();
}

#[task(binds = GPIOB, priority = 3, local = [times: u32 = 0], shared = [s3, s4])]
fn t1(mut cx: t1::Context) {
// Safe access to local `static mut` variable
*cx.local.times += 1;

hprintln!(
"t1 p3 called {} time{}",
*cx.local.times,
if *cx.local.times > 1 { "s" } else { "" }
)
.ok();

cx.shared.s4.lock(|s| {
hprintln!("t1 enter lock s4 {}", s).ok();
hprintln!("t1 pend t0").ok();
rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 2
hprintln!("t1 pend t2").ok();
rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing
hprintln!("t1 still in lock s4 {}", s).ok();
});

hprintln!("t1 p3 exit").ok();
}

#[task(binds = GPIOC, priority = 4, local = [times: u32 = 0], shared = [s4])]
fn t2(mut cx: t2::Context) {
// Safe access to local `static mut` variable
*cx.local.times += 1;

hprintln!(
"t2 p4 called {} time{}",
*cx.local.times,
if *cx.local.times > 1 { "s" } else { "" }
)
.unwrap();

cx.shared.s4.lock(|s| {
hprintln!("enter lock s4 {}", s).ok();
*s += 1;
});
hprintln!("t3 p4 exit").ok();
}
}
2 changes: 1 addition & 1 deletion macros/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
let mut user = vec![];

// Generate the `main` function
let assertion_stmts = assertions::codegen(app, analysis);
let assertion_stmts = assertions::codegen(app, analysis, extra);

let pre_init_stmts = pre_init::codegen(app, analysis, extra);

Expand Down
32 changes: 30 additions & 2 deletions macros/src/codegen/assertions.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;

use crate::analyze::Analysis;
use crate::{analyze::Analysis, check::Extra, codegen::util};
use rtic_syntax::ast::App;

/// Generates compile-time assertions that check that types implement the `Send` / `Sync` traits
pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
let mut stmts = vec![];

for ty in &analysis.send_types {
Expand All @@ -21,5 +21,33 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
stmts.push(quote!(rtic::export::assert_monotonic::<#ty>();));
}

let device = &extra.device;
let arm_v6_checks: Vec<_> = app
.hardware_tasks
.iter()
.filter_map(|(_, task)| {
if !util::is_exception(&task.args.binds) {
let interrupt_name = &task.args.binds;
Some(quote!(assert!((#device::Interrupt::#interrupt_name as u32) < 32);))
} else {
None
}
})
.collect();

let const_check = quote! {
const _CONST_CHECK: () = {
if rtic::export::is_armv6() {
#(#arm_v6_checks)*
} else {
// TODO: Add armv7 checks here
}
};

let _ = _CONST_CHECK;
};

stmts.push(const_check);

stmts
}
33 changes: 33 additions & 0 deletions macros/src/codegen/shared_resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,38 @@ pub fn codegen(
})
};

// Computing mapping of used interrupts to masks
let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id));

use std::collections::HashMap;
let mut masks: HashMap<u8, _> = std::collections::HashMap::new();
let device = &extra.device;

for p in 0..3 {
masks.insert(p, quote!(0));
}

for (&priority, name) in interrupt_ids.chain(app.hardware_tasks.values().flat_map(|task| {
if !util::is_exception(&task.args.binds) {
Some((&task.args.priority, &task.args.binds))
} else {
// TODO: exceptions not implemented
None
}
})) {
let name = quote!(#device::Interrupt::#name as u32);
if let Some(v) = masks.get_mut(&(priority - 1)) {
*v = quote!(#v | 1 << #name);
};
}

let mut mask_arr: Vec<(_, _)> = masks.iter().collect();
mask_arr.sort_by_key(|(k, _v)| *k);
let mask_arr: Vec<_> = mask_arr.iter().map(|(_, v)| v).collect();

mod_app.push(quote!(
const MASKS: [u32; 3] = [#(#mask_arr),*];
));

(mod_app, mod_resources)
}
1 change: 1 addition & 0 deletions macros/src/codegen/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub fn impl_mutex(
#priority,
CEILING,
#device::NVIC_PRIO_BITS,
&MASKS,
f,
)
}
Expand Down
Loading

0 comments on commit a765f3f

Please sign in to comment.