aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jorge Aparicio <japaricious@gmail.com> 2017-02-28 09:59:03 -0500
committerGravatar Jorge Aparicio <japaricious@gmail.com> 2017-02-28 10:04:01 -0500
commit4979a7d3831cdfd50133edff04711f8190b16021 (patch)
tree7fdef03c10080df2ae0787f8390325702ebb3387 /src
parent3f4c581a9cd52c4ad14da2d7008d004a2d888f36 (diff)
downloadcortex-m-4979a7d3831cdfd50133edff04711f8190b16021.tar.gz
cortex-m-4979a7d3831cdfd50133edff04711f8190b16021.tar.zst
cortex-m-4979a7d3831cdfd50133edff04711f8190b16021.zip
changes to better integrate with svd2rust
Diffstat (limited to 'src')
-rw-r--r--src/exception.rs73
-rw-r--r--src/interrupt.rs6
-rw-r--r--src/lib.rs29
-rw-r--r--src/macros.rs29
-rw-r--r--src/peripheral/nvic.rs109
5 files changed, 227 insertions, 19 deletions
diff --git a/src/exception.rs b/src/exception.rs
index 7046080..fad3ea9 100644
--- a/src/exception.rs
+++ b/src/exception.rs
@@ -1,3 +1,7 @@
+//! Exceptions
+
+use {Handler, Reserved, StackFrame};
+
/// Kind of exception
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Exception {
@@ -41,7 +45,76 @@ impl Exception {
15 => Exception::Systick,
n if n >= 16 => Exception::Interrupt(n - 16),
_ => Exception::Reserved,
+ }
+ }
+}
+/// Exception handlers
+#[repr(C)]
+pub struct Handlers {
+ /// Non-maskable interrupt
+ pub nmi: Handler,
+ /// All class of fault
+ pub hard_fault: Handler,
+ /// Memory management
+ pub mem_manage: Handler,
+ /// Pre-fetch fault, memory access fault
+ pub bus_fault: Handler,
+ /// Undefined instruction or illegal state
+ pub usage_fault: Handler,
+ /// Reserved spots in the vector table
+ pub _reserved0: [Reserved; 4],
+ /// System service call via SWI instruction
+ pub svcall: Handler,
+ /// Reserved spots in the vector table
+ pub _reserved1: [Reserved; 2],
+ /// Pendable request for system service
+ pub pendsv: Handler,
+ /// System tick timer
+ pub sys_tick: Handler,
+}
+
+/// Default exception handlers
+pub const DEFAULT_HANDLERS: Handlers = Handlers {
+ _reserved0: [Reserved::Vector; 4],
+ _reserved1: [Reserved::Vector; 2],
+ bus_fault: default_handler,
+ hard_fault: default_handler,
+ mem_manage: default_handler,
+ nmi: default_handler,
+ pendsv: default_handler,
+ svcall: default_handler,
+ sys_tick: default_handler,
+ usage_fault: default_handler,
+};
+
+/// The default exception handler
+///
+/// This handler triggers a breakpoint (`bkpt`) and gives you access, within a
+/// GDB session, to the stack frame (`_sf`) where the exception occurred.
+// This needs asm!, #[naked] and unreachable() to avoid modifying the stack
+// pointer (MSP), that way it points to the previous stack frame
+#[naked]
+pub unsafe extern "C" fn default_handler() {
+ // This is the actual exception handler. `_sf` is a pointer to the previous
+ // stack frame
+ extern "C" fn handler(_sf: &StackFrame) -> ! {
+ #[cfg(feature = "semihosting")]
+ hprintln!("EXCEPTION {:?} @ PC=0x{:08x}", Exception::current(), _sf.pc);
+
+ unsafe {
+ bkpt!();
}
+
+ loop {}
}
+
+ // "trampoline" to get to the real exception handler.
+ asm!("mrs r0, MSP
+ ldr r1, [r0, #20]
+ b $0"
+ :
+ : "i"(handler as extern "C" fn(&StackFrame) -> !) :: "volatile");
+
+ ::core::intrinsics::unreachable()
}
diff --git a/src/interrupt.rs b/src/interrupt.rs
index 4305071..035dcd4 100644
--- a/src/interrupt.rs
+++ b/src/interrupt.rs
@@ -26,6 +26,12 @@ impl<T> Mutex<T> {
}
}
+/// Interrupt number
+pub unsafe trait Nr {
+ /// Returns the number associated with this interrupt
+ fn nr(&self) -> u8;
+}
+
// FIXME `T` should have some bound: `Send` or `Sync`?
unsafe impl<T> Sync for Mutex<T> {}
diff --git a/src/lib.rs b/src/lib.rs
index 09eeceb..5e75d53 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -7,25 +7,30 @@
//! - Interrupt manipulation mechanisms
//! - Data structures like the vector table
//! - Miscellaneous assembly instructions like `bkpt`
-//!
+#![cfg_attr(feature = "semihosting", feature(macro_reexport))]
#![deny(missing_docs)]
#![deny(warnings)]
#![feature(asm)]
#![feature(const_fn)]
+#![feature(core_intrinsics)]
+#![feature(naked_functions)]
#![no_std]
+#[cfg(feature = "semihosting")]
+pub extern crate cortex_m_semihosting as semihosting;
extern crate volatile_register;
+#[macro_use]
+mod macros;
+
+#[macro_use]
pub mod asm;
+pub mod exception;
pub mod interrupt;
pub mod peripheral;
pub mod register;
-mod exception;
-
-pub use exception::Exception;
-
/// Stack frame
#[repr(C)]
pub struct StackFrame {
@@ -82,14 +87,22 @@ pub struct VectorTable {
pub interrupts: [Option<Handler>; 0],
}
-/// Returns the vector table
-pub fn vector_table() -> &'static VectorTable {
- unsafe { deref(peripheral::scb().vtor.read() as usize) }
+/// A reserved spot in the vector table
+#[derive(Clone, Copy)]
+#[repr(u32)]
+pub enum Reserved {
+ /// Reserved
+ Vector = 0,
}
/// Exception/Interrupt Handler
pub type Handler = unsafe extern "C" fn();
+/// Returns the vector table
+pub fn vector_table() -> &'static VectorTable {
+ unsafe { deref(peripheral::scb().vtor.read() as usize) }
+}
+
#[cfg(test)]
fn address<T>(r: &T) -> usize {
r as *const T as usize
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..bd31167
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,29 @@
+/// Macro for printing to the **host's** standard stderr
+#[macro_export]
+macro_rules! ehprint {
+ ($s:expr) => ($crate::semihosting:::io:ewrite_str($s));
+ ($($arg:tt)*) => ($crate::semihosting::io::ewrite_fmt(format_args!($($arg)*)));
+}
+
+/// Macro for printing to the **host's** standard error, with a newline.
+#[macro_export]
+macro_rules! ehprintln {
+ () => (ehprint!("\n"));
+ ($fmt:expr) => (ehprint!(concat!($fmt, "\n")));
+ ($fmt:expr, $($arg:tt)*) => (ehprint!(concat!($fmt, "\n"), $($arg)*));
+}
+
+/// Macro for printing to the **host's** standard output
+#[macro_export]
+macro_rules! hprint {
+ ($s:expr) => ($crate::semihosting::io::write_str($s));
+ ($($arg:tt)*) => ($crate::semihosting::io::write_fmt(format_args!($($arg)*)));
+}
+
+/// Macro for printing to the **host's** standard output, with a newline.
+#[macro_export]
+macro_rules! hprintln {
+ () => (hprint!("\n"));
+ ($fmt:expr) => (hprint!(concat!($fmt, "\n")));
+ ($fmt:expr, $($arg:tt)*) => (hprint!(concat!($fmt, "\n"), $($arg)*));
+}
diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs
index 4570c0f..64adc90 100644
--- a/src/peripheral/nvic.rs
+++ b/src/peripheral/nvic.rs
@@ -1,25 +1,112 @@
//! Nested Vector Interrupt Controller
+use interrupt::Nr;
use volatile_register::{RO, RW};
/// Registers
#[repr(C)]
pub struct Registers {
/// Interrupt Set-Enable
- pub iser: [RW<u32>; 16],
- reserved0: [u32; 16],
+ pub iser: [RW<u32>; 8],
+ reserved0: [u32; 24],
/// Interrupt Clear-Enable
- pub icer: [RW<u32>; 16],
- reserved1: [u32; 16],
+ pub icer: [RW<u32>; 8],
+ reserved1: [u32; 24],
/// Interrupt Set-Pending
- pub ispr: [RW<u32>; 16],
- reserved2: [u32; 16],
+ pub ispr: [RW<u32>; 8],
+ reserved2: [u32; 24],
/// Interrupt Clear-Pending
- pub icpr: [RW<u32>; 16],
- reserved3: [u32; 16],
+ pub icpr: [RW<u32>; 8],
+ reserved3: [u32; 24],
/// Interrupt Active Bit
- pub iabr: [RO<u32>; 16],
- reserved4: [u32; 48],
+ pub iabr: [RO<u32>; 8],
+ reserved4: [u32; 56],
/// Interrupt Priority
- pub ipr: [RW<u32>; 124],
+ pub ipr: [RW<u8>; 240],
+}
+
+impl Registers {
+ /// Clears `interrupt` pending state
+ pub fn clear_pending<I>(&mut self, interrupt: I)
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ self.icpr[usize::from(nr / 32)].write(1 << (nr % 32));
+ }
+
+ /// Disables `interrupt`
+ pub fn disable<I>(&mut self, interrupt: I)
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ self.icer[usize::from(nr / 32)].write(1 << (nr % 32));
+ }
+
+ /// Enables `interrupt`
+ pub fn enable<I>(&mut self, interrupt: I)
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ self.iser[usize::from(nr / 32)].write(1 << (nr % 32));
+ }
+
+ /// Gets the priority of `interrupt`
+ pub fn get_priority<I>(&mut self, interrupt: I) -> u8
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ self.ipr[usize::from(nr / 4)].read()
+ }
+
+ /// Is `interrupt` active or pre-empted and stacked
+ pub fn is_active<I>(&self, interrupt: I) -> bool
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+ let mask = 1 << (nr % 32);
+
+ (self.iabr[usize::from(nr / 32)].read() & mask) == mask
+ }
+
+ /// Checks if `interrupt` is enabled
+ pub fn is_enabled<I>(&self, interrupt: I) -> bool
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+ let mask = 1 << (nr % 32);
+
+ (self.iser[usize::from(nr / 32)].read() & mask) == mask
+ }
+
+ /// Checks if `interrupt` is pending
+ pub fn is_pending<I>(&self, interrupt: I) -> bool
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+ let mask = 1 << (nr % 32);
+
+ (self.ispr[usize::from(nr / 32)].read() & mask) == mask
+ }
+
+ /// Forces `interrupt` into pending state
+ pub fn set_pending<I>(&mut self, interrupt: I)
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ self.ispr[usize::from(nr / 32)].write(1 << (nr % 32));
+ }
+
+ /// Sets the priority of `interrupt` to `prio`
+ pub fn set_priority<I>(&mut self, interrupt: I, prio: u8)
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ self.ipr[usize::from(nr / 4)].write(prio);
+ }
}