Skip to content

Commit f491bb8

Browse files
committed
rewrite NVIC to use derive-mmio
1 parent d232aaf commit f491bb8

3 files changed

Lines changed: 113 additions & 68 deletions

File tree

cortex-m/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ rust-version = "1.85"
1515
[dependencies]
1616
bare-metal = { version = "0.2.4", features = ["const-fn"] }
1717
critical-section = "1.0.0"
18+
derive-mmio = "0.6"
1819
volatile-register = "0.2.2"
1920
bitfield = "0.13.2"
2021
eh0 = { package = "embedded-hal", version = "0.2.4" }

cortex-m/src/peripheral/mod.rs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,7 @@ impl Peripherals {
206206
MPU: MPU {
207207
_marker: PhantomData,
208208
},
209-
NVIC: NVIC {
210-
_marker: PhantomData,
211-
},
209+
NVIC: NVIC(nvic::RegisterBlock::new()),
212210
SAU: SAU {
213211
_marker: PhantomData,
214212
},
@@ -536,30 +534,35 @@ impl ops::Deref for MPU {
536534
}
537535

538536
/// Nested Vector Interrupt Controller
539-
pub struct NVIC {
540-
_marker: PhantomData<*const ()>,
541-
}
537+
pub struct NVIC(nvic::MmioRegisterBlock<'static>);
542538

543539
unsafe impl Send for NVIC {}
544540

545541
impl NVIC {
546-
/// Pointer to the register block
547-
pub const PTR: *const nvic::RegisterBlock = 0xE000_E100 as *const _;
548-
549-
/// Returns a pointer to the register block
550-
#[inline(always)]
551-
#[deprecated(since = "0.7.5", note = "Use the associated constant `PTR` instead")]
552-
pub const fn ptr() -> *const nvic::RegisterBlock {
553-
Self::PTR
542+
/// Unsafely steal an instance of the NVIC.
543+
///
544+
/// # Safety
545+
///
546+
/// This potentially allows to create multiple instances of the NVIC register block, which
547+
/// might only be valid in certain multi-core environments.
548+
pub unsafe fn steal() -> Self {
549+
NVIC(unsafe { nvic::RegisterBlock::new() })
554550
}
555551
}
556552

557553
impl ops::Deref for NVIC {
558-
type Target = self::nvic::RegisterBlock;
554+
type Target = nvic::MmioRegisterBlock<'static>;
559555

560556
#[inline(always)]
561557
fn deref(&self) -> &Self::Target {
562-
unsafe { &*Self::PTR }
558+
&self.0
559+
}
560+
}
561+
562+
impl ops::DerefMut for NVIC {
563+
#[inline(always)]
564+
fn deref_mut(&mut self) -> &mut Self::Target {
565+
&mut self.0
563566
}
564567
}
565568

cortex-m/src/peripheral/nvic.rs

Lines changed: 93 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,42 @@
11
//! Nested Vector Interrupt Controller
2-
3-
use volatile_register::RW;
4-
#[cfg(not(armv6m))]
5-
use volatile_register::{RO, WO};
6-
72
use crate::interrupt::InterruptNumber;
83
use crate::peripheral::NVIC;
94

10-
/// Register block
5+
/// NVIC register block.
6+
#[derive(derive_mmio::Mmio)]
117
#[repr(C)]
128
pub struct RegisterBlock {
139
/// Interrupt Set-Enable
14-
pub iser: [RW<u32>; 16],
10+
iser: [u32; 16],
1511

1612
_reserved0: [u32; 16],
1713

1814
/// Interrupt Clear-Enable
19-
pub icer: [RW<u32>; 16],
15+
icer: [u32; 16],
2016

2117
_reserved1: [u32; 16],
2218

2319
/// Interrupt Set-Pending
24-
pub ispr: [RW<u32>; 16],
20+
ispr: [u32; 16],
2521

2622
_reserved2: [u32; 16],
2723

2824
/// Interrupt Clear-Pending
29-
pub icpr: [RW<u32>; 16],
25+
icpr: [u32; 16],
3026

3127
_reserved3: [u32; 16],
3228

3329
/// Interrupt Active Bit (not present on Cortex-M0 variants)
3430
#[cfg(not(armv6m))]
35-
pub iabr: [RO<u32>; 16],
31+
iabr: [u32; 16],
3632
#[cfg(armv6m)]
3733
_reserved4: [u32; 16],
3834

3935
_reserved5: [u32; 16],
4036

4137
#[cfg(armv8m)]
4238
/// Interrupt Target Non-secure (only present on Arm v8-M)
43-
pub itns: [RW<u32>; 16],
39+
itns: [u32; 16],
4440
#[cfg(not(armv8m))]
4541
_reserved6: [u32; 16],
4642

@@ -58,7 +54,7 @@ pub struct RegisterBlock {
5854
/// so convenient byte-sized representation wouldn't work on that
5955
/// architecture.
6056
#[cfg(not(armv6m))]
61-
pub ipr: [RW<u8>; 496],
57+
ipr: [u32; 124],
6258

6359
/// Interrupt Priority
6460
///
@@ -72,14 +68,26 @@ pub struct RegisterBlock {
7268
/// so convenient byte-sized representation wouldn't work on that
7369
/// architecture.
7470
#[cfg(armv6m)]
75-
pub ipr: [RW<u32>; 8],
71+
ipr: [u32; 8],
7672

7773
#[cfg(not(armv6m))]
7874
_reserved8: [u32; 580],
7975

8076
/// Software Trigger Interrupt
8177
#[cfg(not(armv6m))]
82-
pub stir: WO<u32>,
78+
stir: u32,
79+
}
80+
81+
impl RegisterBlock {
82+
/// Creates a new instance of the NVIC register block.
83+
///
84+
/// # Safety
85+
///
86+
/// This potentially allows to create multiple instances of the NVIC register block, which
87+
/// might only be valid in certain multi-core environments.
88+
pub const unsafe fn new() -> MmioRegisterBlock<'static> {
89+
unsafe { RegisterBlock::new_mmio_at(0xE000_E100) }
90+
}
8391
}
8492

8593
impl NVIC {
@@ -100,9 +108,7 @@ impl NVIC {
100108
{
101109
let nr = interrupt.number();
102110

103-
unsafe {
104-
self.stir.write(u32::from(nr));
105-
}
111+
self.write_stir(u32::from(nr));
106112
}
107113

108114
/// Disables `interrupt`
@@ -113,7 +119,8 @@ impl NVIC {
113119
{
114120
let nr = interrupt.number();
115121
// NOTE(unsafe) this is a write to a stateless register
116-
unsafe { (*Self::PTR).icer[usize::from(nr / 32)].write(1 << (nr % 32)) }
122+
let mut nvic = unsafe { Self::steal() };
123+
nvic.write_icer(usize::from(nr / 32), 1 << (nr % 32)).expect("invalid interrupt number");
117124
}
118125

119126
/// Enables `interrupt`
@@ -124,11 +131,10 @@ impl NVIC {
124131
where
125132
I: InterruptNumber,
126133
{
127-
unsafe {
128-
let nr = interrupt.number();
129-
// NOTE(ptr) this is a write to a stateless register
130-
(*Self::PTR).iser[usize::from(nr / 32)].write(1 << (nr % 32))
131-
}
134+
let nr = interrupt.number();
135+
// NOTE(ptr) this is a write to a stateless register
136+
let mut nvic = unsafe { Self::steal() };
137+
nvic.write_iser(usize::from(nr / 32), 1 << (nr % 32)).expect("invalid interrupt number");
132138
}
133139

134140
/// Returns the NVIC priority of `interrupt`
@@ -144,16 +150,26 @@ impl NVIC {
144150
#[cfg(not(armv6m))]
145151
{
146152
let nr = interrupt.number();
147-
// NOTE(unsafe) atomic read with no side effects
148-
unsafe { (*Self::PTR).ipr[usize::from(nr)].read() }
153+
// note(unsafe) atomic read with no side effects
154+
let nvic = unsafe { Self::steal() };
155+
let ipr_ptr = nvic.pointer_to_ipr_start() as *const u8;
156+
// This should never happen for correct `InterruptNumber` implementations.
157+
if nr >= 124 {
158+
panic!("unexpected interrupt number");
159+
}
160+
// note(unsafe) atomic read with no side effects
161+
unsafe { core::ptr::read_volatile(ipr_ptr.offset(nr as isize)) }
149162
}
150163

151164
#[cfg(armv6m)]
152165
{
153-
// NOTE(unsafe) atomic read with no side effects
154-
let ipr_n = unsafe { (*Self::PTR).ipr[Self::ipr_index(interrupt)].read() };
155-
let prio = (ipr_n >> Self::ipr_shift(interrupt)) & 0x0000_00ff;
156-
prio as u8
166+
// note(unsafe) atomic read with no side effects
167+
let nvic = unsafe { Self::steal() };
168+
let ipr_index = Self::ipr_index();
169+
let iprn_n = nvic
170+
.read_ipr(Self::ipr_index(interrupt))
171+
.expect("unexpected interrupt number");
172+
let prio = ((ipr_n >> Self::ipr_shift(interrupt)) & 0x0000_00ff) as u8;
157173
}
158174
}
159175

@@ -167,8 +183,12 @@ impl NVIC {
167183
let nr = interrupt.number();
168184
let mask = 1 << (nr % 32);
169185

170-
// NOTE(unsafe) atomic read with no side effects
171-
unsafe { ((*Self::PTR).iabr[usize::from(nr / 32)].read() & mask) == mask }
186+
// note(unsafe) atomic read with no side effects
187+
let nvic = unsafe { Self::steal() };
188+
nvic.read_iabr(usize::from(nr / 32))
189+
.expect("unexpected interrupt number")
190+
& mask
191+
== mask
172192
}
173193

174194
/// Checks if `interrupt` is enabled
@@ -180,8 +200,12 @@ impl NVIC {
180200
let nr = interrupt.number();
181201
let mask = 1 << (nr % 32);
182202

183-
// NOTE(unsafe) atomic read with no side effects
184-
unsafe { ((*Self::PTR).iser[usize::from(nr / 32)].read() & mask) == mask }
203+
// note(unsafe) atomic read with no side effects
204+
let nvic = unsafe { Self::steal() };
205+
nvic.read_iser(usize::from(nr / 32))
206+
.expect("unexpected interrupt number")
207+
& mask
208+
== mask
185209
}
186210

187211
/// Checks if `interrupt` is pending
@@ -193,8 +217,12 @@ impl NVIC {
193217
let nr = interrupt.number();
194218
let mask = 1 << (nr % 32);
195219

196-
// NOTE(unsafe) atomic read with no side effects
197-
unsafe { ((*Self::PTR).ispr[usize::from(nr / 32)].read() & mask) == mask }
220+
// note(unsafe) atomic read with no side effects
221+
let nvic = unsafe { Self::steal() };
222+
nvic.read_ispr(usize::from(nr / 32))
223+
.expect("unexpected interrupt number")
224+
& mask
225+
== mask
198226
}
199227

200228
/// Forces `interrupt` into pending state
@@ -206,7 +234,9 @@ impl NVIC {
206234
let nr = interrupt.number();
207235

208236
// NOTE(unsafe) atomic stateless write; ICPR doesn't store any state
209-
unsafe { (*Self::PTR).ispr[usize::from(nr / 32)].write(1 << (nr % 32)) }
237+
let mut nvic = unsafe { Self::steal() };
238+
nvic.write_ispr(usize::from(nr / 32), 1 << (nr % 32))
239+
.expect("unexpected interrupt number")
210240
}
211241

212242
/// Sets the "priority" of `interrupt` to `prio`
@@ -226,22 +256,31 @@ impl NVIC {
226256
where
227257
I: InterruptNumber,
228258
{
229-
unsafe {
230-
#[cfg(not(armv6m))]
231-
{
232-
let nr = interrupt.number();
233-
self.ipr[usize::from(nr)].write(prio)
259+
#[cfg(not(armv6m))]
260+
{
261+
let nr = interrupt.number();
262+
// NOTE(unsafe) atomic stateless write; IPR doesn't store any state
263+
let nvic = unsafe { Self::steal() };
264+
let ipr_ptr = nvic.pointer_to_ipr_start() as *mut u8;
265+
// This should never happen for correct `InterruptNumber` implementations.
266+
if nr >= 124 {
267+
panic!("unexpected interrupt number");
234268
}
269+
// NOTE(unsafe) atomic stateless write; IPR doesn't store any state
270+
unsafe { core::ptr::write_volatile(ipr_ptr.offset(nr as isize), prio) }
271+
}
235272

236-
#[cfg(armv6m)]
237-
{
238-
self.ipr[Self::ipr_index(interrupt)].modify(|value| {
239-
let mask = 0x0000_00ff << Self::ipr_shift(interrupt);
240-
let prio = u32::from(prio) << Self::ipr_shift(interrupt);
241-
242-
(value & !mask) | prio
243-
})
244-
}
273+
#[cfg(armv6m)]
274+
{
275+
// NOTE(unsafe) atomic stateless write; IPR doesn't store any state
276+
let nvic = unsafe { Self::steal() };
277+
nvic.modify_ipr(Self::ipr_index(interrupt), |mut val| {
278+
let mask = 0x0000_00ff << Self::ipr_shift(interrupt);
279+
let prio = u32::from(prio) << Self::ipr_shift(interrupt);
280+
281+
(value & !mask) | prio
282+
})
283+
.expect("unexpected interrupt number");
245284
}
246285
}
247286

@@ -254,7 +293,9 @@ impl NVIC {
254293
let nr = interrupt.number();
255294

256295
// NOTE(unsafe) atomic stateless write; ICPR doesn't store any state
257-
unsafe { (*Self::PTR).icpr[usize::from(nr / 32)].write(1 << (nr % 32)) }
296+
let mut nvic = unsafe { Self::steal() };
297+
nvic.write_icpr(usize::from(nr / 32), 1 << (nr % 32))
298+
.expect("unexpected interrupt number")
258299
}
259300

260301
#[cfg(armv6m)]

0 commit comments

Comments
 (0)