Skip to content

Commit 2885f69

Browse files
author
Jorge Aparicio
authored
Merge pull request #17 from japaric/ng
v0.2.0
2 parents 3f4c581 + 173b5bc commit 2885f69

37 files changed

+1624
-818
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
dist: trusty
22
language: rust
3-
rust: nightly
3+
rust: nightly-2017-03-04
44
services: docker
55
sudo: required
66

CHANGELOG.md

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,50 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Semihosting functionality in the `semihosting` module.
13+
14+
- `exception::Handlers` struct that represent the section of the vector table
15+
that contains the exception handlers.
16+
17+
- A default exception handler
18+
19+
- A high level API for the NVIC peripheral.
20+
21+
- Context local data.
22+
23+
- `borrow`/`borrow_mut` methods to `Mutex` that replace `lock`.
24+
25+
- API and macros to send bytes / (formatted) strings through ITM
26+
27+
### Changed
28+
29+
- [breaking-change] `StackFrame` has been renamed to `StackedRegisters` and
30+
moved into the `exceptions` module.
31+
32+
- [breaking-change] Core peripherals can now be modified via a `&-` reference
33+
and are no longer `Sync`.
34+
35+
- [breaking-change] `interrupt::free`'s closure now includes a critical section
36+
token, `CriticalSection`.
37+
38+
- [breaking-change] the core register API has been revamped for type safety.
39+
40+
- The safety of assembly wrappers like `wfi` and `interrupt::free` has been
41+
reviewed. In many cases, the functions are no longer unsafe.
42+
43+
- [breaking-change] `bkpt!` has been turned into a function. It no longer
44+
accepts an immediate value.
45+
46+
### Removed
47+
48+
- `vector_table` and its associated `struct`, `VectorTable`. It's not a good
49+
idea to give people a simple way to call the exception handlers.
50+
51+
- `Mutex`'s `lock` method as it's unsound. You could use it to get multiple
52+
`&mut -` references to the wrapped data.
53+
1054
## [v0.1.6] - 2017-01-22
1155

1256
### Added
@@ -60,10 +104,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
60104
- Functions to get the vector table
61105
- Wrappers over miscellaneous instructions like `bkpt`
62106

63-
[Unreleased]: https://github.com/japaric/rustc-cfg/compare/v0.1.6...HEAD
64-
[v0.1.6]: https://github.com/japaric/rustc-cfg/compare/v0.1.5...v0.1.6
65-
[v0.1.5]: https://github.com/japaric/rustc-cfg/compare/v0.1.4...v0.1.5
66-
[v0.1.4]: https://github.com/japaric/rustc-cfg/compare/v0.1.3...v0.1.4
67-
[v0.1.3]: https://github.com/japaric/rustc-cfg/compare/v0.1.2...v0.1.3
68-
[v0.1.2]: https://github.com/japaric/rustc-cfg/compare/v0.1.1...v0.1.2
69-
[v0.1.1]: https://github.com/japaric/rustc-cfg/compare/v0.1.0...v0.1.1
107+
[Unreleased]: https://github.com/japaric/cortex-m/compare/v0.1.6...HEAD
108+
[v0.1.6]: https://github.com/japaric/cortex-m/compare/v0.1.5...v0.1.6
109+
[v0.1.5]: https://github.com/japaric/cortex-m/compare/v0.1.4...v0.1.5
110+
[v0.1.4]: https://github.com/japaric/cortex-m/compare/v0.1.3...v0.1.4
111+
[v0.1.3]: https://github.com/japaric/cortex-m/compare/v0.1.2...v0.1.3
112+
[v0.1.2]: https://github.com/japaric/cortex-m/compare/v0.1.1...v0.1.2
113+
[v0.1.1]: https://github.com/japaric/cortex-m/compare/v0.1.0...v0.1.1

Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ keywords = ["arm", "cortex-m", "register", "peripheral"]
66
license = "MIT OR Apache-2.0"
77
name = "cortex-m"
88
repository = "https://github.com/japaric/cortex-m"
9-
version = "0.1.6"
9+
version = "0.2.0"
1010

1111
[dependencies]
12-
volatile-register = "0.1.0"
12+
volatile-register = "0.2.0"
13+
14+
[dependencies.cortex-m-semihosting]
15+
version = "0.1.3"

build.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use std::env;
2+
3+
fn main() {
4+
let target = env::var("TARGET").unwrap();
5+
6+
if target.starts_with("thumbv6m-") {
7+
println!("cargo:rustc-cfg=armv6m")
8+
}
9+
}

ci/install.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@ main() {
44
curl https://sh.rustup.rs -sSf | \
55
sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION
66

7+
local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
8+
| cut -d/ -f3 \
9+
| grep -E '^v[0-9.]+$' \
10+
| sort --version-sort \
11+
| tail -n1)
712
curl -LSfs http://japaric.github.io/trust/install.sh | \
813
sh -s -- \
914
--force \
1015
--git japaric/cross \
11-
--tag v0.1.2 \
16+
--tag $tag \
1217
--target x86_64-unknown-linux-musl \
1318
--to ~/.cargo/bin
1419
}

src/asm.rs

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,60 @@
11
//! Miscellaneous assembly instructions
22
3-
/// Puts the processor in Debug state. Debuggers can pick this up as a "breakpoint".
3+
/// Puts the processor in Debug state. Debuggers can pick this up as a
4+
/// "breakpoint".
45
///
5-
/// Optionally, an "immediate" value (in the 0-255 range) can be passed to `bkpt!`. The debugger can
6-
/// then read this value using the Program Counter (PC).
7-
#[cfg(target_arch = "arm")]
8-
#[macro_export]
9-
macro_rules! bkpt {
10-
() => {
11-
asm!("bkpt" :::: "volatile");
12-
};
13-
($imm:expr) => {
14-
asm!(concat!("bkpt #", stringify!($imm)) :::: "volatile");
15-
};
6+
/// NOTE calling `bkpt` when the processor is not connected to a debugger will
7+
/// cause an exception
8+
#[inline(always)]
9+
pub fn bkpt() {
10+
#[cfg(target_arch = "arm")]
11+
unsafe {
12+
asm!("bkpt"
13+
:
14+
:
15+
:
16+
: "volatile");
17+
}
1618
}
1719

18-
/// Puts the processor in Debug state. Debuggers can pick this up as a "breakpoint".
19-
///
20-
/// Optionally, an "immediate" value (in the 0-255 range) can be passed to `bkpt!`. The debugger can
21-
/// then read this value using the Program Counter (PC).
22-
#[cfg(not(target_arch = "arm"))]
23-
#[macro_export]
24-
macro_rules! bkpt {
25-
() => {
26-
asm!("nop" :::: "volatile");
27-
};
28-
($e:expr) => {
29-
asm!("nop" :::: "volatile");
30-
};
20+
/// A no-operation. Useful to prevent delay loops from being optimized away.
21+
pub fn nop() {
22+
unsafe {
23+
asm!("nop"
24+
:
25+
:
26+
:
27+
: "volatile");
28+
}
3129
}
32-
33-
/// Wait for event
34-
pub unsafe fn wfe() {
30+
/// Wait For Event
31+
pub fn wfe() {
3532
match () {
3633
#[cfg(target_arch = "arm")]
37-
() => asm!("wfe" :::: "volatile"),
34+
() => unsafe {
35+
asm!("wfe"
36+
:
37+
:
38+
:
39+
: "volatile")
40+
},
3841
#[cfg(not(target_arch = "arm"))]
3942
() => {}
4043
}
4144
}
4245

43-
/// Wait for interupt
44-
pub unsafe fn wfi() {
46+
/// Wait For Interrupt
47+
pub fn wfi() {
4548
match () {
4649
#[cfg(target_arch = "arm")]
47-
() => asm!("wfi" :::: "volatile"),
50+
() => unsafe{
51+
asm!("wfi"
52+
:
53+
:
54+
:
55+
: "volatile")
56+
},
4857
#[cfg(not(target_arch = "arm"))]
4958
() => {}
5059
}
5160
}
52-
53-
/// A no-operation. Useful to stop delay loops being elided.
54-
pub fn nop() {
55-
unsafe {
56-
asm!("nop" :::: "volatile");
57-
}
58-
}

src/ctxt.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//! Interrupt / Exception context local data
2+
//!
3+
//! The main use case is safely adding state to exception / interrupt handlers.
4+
//!
5+
//! This is done in two stages, first you define a token that will appear in the
6+
//! interrupt handler signature; each handler will have its unique token. This
7+
//! token must be zero sized type because interrupt handlers' real signature is
8+
//! `fn()` and it must also implement the `Context` trait. You must also make
9+
//! sure that the token can't be constructed outside of the crate where it's
10+
//! defined.
11+
//!
12+
//! ```
13+
//! # use cortex_m::ctxt::Context;
14+
//! // This must be in a library crate
15+
//! /// Token unique to the TIM7 interrupt handler
16+
//! pub struct Tim7 { _0: () }
17+
//!
18+
//! unsafe impl Context for Tim7 {}
19+
//! ```
20+
//!
21+
//! Then in the application one can pin data to the interrupt handler using
22+
//! `Local`.
23+
//!
24+
//! ```
25+
//! # #![feature(const_fn)]
26+
//! # use std::cell::Cell;
27+
//! # use cortex_m::ctxt::{Context, Local};
28+
//! # struct Tim7;
29+
//! # unsafe impl Context for Tim7 {}
30+
//! // omitted: how to put this handler in the vector table
31+
//! extern "C" fn tim7(ctxt: Tim7) {
32+
//! static STATE: Local<Cell<bool>, Tim7> = Local::new(Cell::new(false));
33+
//!
34+
//! let state = STATE.borrow(&ctxt);
35+
//!
36+
//! // toggle state
37+
//! state.set(!state.get());
38+
//!
39+
//! if state.get() {
40+
//! // something
41+
//! } else {
42+
//! // something else
43+
//! }
44+
//! }
45+
//! ```
46+
//!
47+
//! Note that due to the uniqueness of tokens, other handlers won't be able to
48+
//! access context local data. (Given that you got the signatures right)
49+
//!
50+
//! ```
51+
//! # #![feature(const_fn)]
52+
//! # use std::cell::Cell;
53+
//! # use cortex_m::ctxt::{Context, Local};
54+
//! # struct Tim3;
55+
//! # struct Tim4;
56+
//! static TIM3_DATA: Local<Cell<bool>, Tim3> = Local::new(Cell::new(false));
57+
//!
58+
//! extern "C" fn tim3(ctxt: Tim3) {
59+
//! let data = TIM3_DATA.borrow(&ctxt);
60+
//! }
61+
//!
62+
//! extern "C" fn tim4(ctxt: Tim4) {
63+
//! //let data = TIM3_DATA.borrow(&ctxt);
64+
//! // ^ wouldn't work
65+
//! }
66+
//! # unsafe impl Context for Tim3 {}
67+
//! # fn main() {}
68+
//! ```
69+
//!
70+
//! To have the application use these tokenized function signatures, you can
71+
//! define, in a library, a `Handlers` struct that represents the vector table:
72+
//!
73+
//! ```
74+
//! # struct Tim1;
75+
//! # struct Tim2;
76+
//! # struct Tim3;
77+
//! # struct Tim4;
78+
//! # extern "C" fn default_handler<T>(_: T) {}
79+
//! #[repr(C)]
80+
//! pub struct Handlers {
81+
//! tim1: extern "C" fn(Tim1),
82+
//! tim2: extern "C" fn(Tim2),
83+
//! tim3: extern "C" fn(Tim3),
84+
//! tim4: extern "C" fn(Tim4),
85+
//! /* .. */
86+
//! }
87+
//!
88+
//! pub const DEFAULT_HANDLERS: Handlers = Handlers {
89+
//! tim1: default_handler,
90+
//! tim2: default_handler,
91+
//! tim3: default_handler,
92+
//! tim4: default_handler,
93+
//! /* .. */
94+
//! };
95+
//! ```
96+
//!
97+
//! Then have the user use that `struct` to register the interrupt handlers:
98+
//!
99+
//! ```
100+
//! # struct Tim3;
101+
//! # struct Handlers { tim3: extern "C" fn(Tim3), tim4: extern "C" fn(Tim3) }
102+
//! # const DEFAULT_HANDLERS: Handlers = Handlers { tim3: tim3, tim4: tim3 };
103+
//! extern "C" fn tim3(ctxt: Tim3) { /* .. */ }
104+
//!
105+
//! // override the TIM3 interrupt handler
106+
//! #[no_mangle]
107+
//! static _INTERRUPTS: Handlers = Handlers {
108+
//! tim3: tim3, ..DEFAULT_HANDLERS
109+
//! };
110+
//! ```
111+
//!
112+
//! This pattern is implemented for exceptions in this crate. See
113+
//! `exception::Handlers` and `exception::DEFAULT_HANDLERS`.
114+
115+
use core::marker::PhantomData;
116+
use core::cell::UnsafeCell;
117+
118+
/// Data local to a context
119+
pub struct Local<T, Ctxt>
120+
where
121+
Ctxt: Context,
122+
{
123+
_ctxt: PhantomData<Ctxt>,
124+
data: UnsafeCell<T>,
125+
}
126+
127+
impl<T, Ctxt> Local<T, Ctxt>
128+
where
129+
Ctxt: Context,
130+
{
131+
/// Initializes context local data
132+
pub const fn new(value: T) -> Self {
133+
Local {
134+
_ctxt: PhantomData,
135+
data: UnsafeCell::new(value),
136+
}
137+
}
138+
139+
/// Acquires a reference to the context local data
140+
pub fn borrow<'ctxt>(&'static self, _ctxt: &'ctxt Ctxt) -> &'ctxt T {
141+
unsafe { &*self.data.get() }
142+
}
143+
144+
/// Acquires a mutable reference to the context local data
145+
pub fn borrow_mut<'ctxt>(
146+
&'static self,
147+
_ctxt: &'ctxt mut Ctxt,
148+
) -> &'ctxt mut T {
149+
unsafe { &mut *self.data.get() }
150+
}
151+
}
152+
153+
unsafe impl<T, Ctxt> Sync for Local<T, Ctxt>
154+
where
155+
Ctxt: Context,
156+
{
157+
}
158+
159+
/// A token unique to a context
160+
pub unsafe trait Context {}

0 commit comments

Comments
 (0)