11//! Nested Vector Interrupt Controller
2-
3- use volatile_register:: RW ;
4- #[ cfg( not( armv6m) ) ]
5- use volatile_register:: { RO , WO } ;
6-
72use crate :: interrupt:: InterruptNumber ;
83use crate :: peripheral:: NVIC ;
94
10- /// Register block
5+ /// NVIC base address.
6+ pub const BASE_ADDRESS : usize = 0xE000_E100 ;
7+
8+ /// NVIC register block.
9+ #[ derive( derive_mmio:: Mmio ) ]
1110#[ repr( C ) ]
1211pub struct RegisterBlock {
1312 /// Interrupt Set-Enable
14- pub iser : [ RW < u32 > ; 16 ] ,
13+ iser : [ u32 ; 16 ] ,
1514
1615 _reserved0 : [ u32 ; 16 ] ,
1716
1817 /// Interrupt Clear-Enable
19- pub icer : [ RW < u32 > ; 16 ] ,
18+ icer : [ u32 ; 16 ] ,
2019
2120 _reserved1 : [ u32 ; 16 ] ,
2221
2322 /// Interrupt Set-Pending
24- pub ispr : [ RW < u32 > ; 16 ] ,
23+ ispr : [ u32 ; 16 ] ,
2524
2625 _reserved2 : [ u32 ; 16 ] ,
2726
2827 /// Interrupt Clear-Pending
29- pub icpr : [ RW < u32 > ; 16 ] ,
28+ icpr : [ u32 ; 16 ] ,
3029
3130 _reserved3 : [ u32 ; 16 ] ,
3231
3332 /// Interrupt Active Bit (not present on Cortex-M0 variants)
3433 #[ cfg( not( armv6m) ) ]
35- pub iabr : [ RO < u32 > ; 16 ] ,
34+ iabr : [ u32 ; 16 ] ,
3635 #[ cfg( armv6m) ]
3736 _reserved4 : [ u32 ; 16 ] ,
3837
3938 _reserved5 : [ u32 ; 16 ] ,
4039
4140 #[ cfg( armv8m) ]
4241 /// Interrupt Target Non-secure (only present on Arm v8-M)
43- pub itns : [ RW < u32 > ; 16 ] ,
42+ itns : [ u32 ; 16 ] ,
4443 #[ cfg( not( armv8m) ) ]
4544 _reserved6 : [ u32 ; 16 ] ,
4645
@@ -58,7 +57,7 @@ pub struct RegisterBlock {
5857 /// so convenient byte-sized representation wouldn't work on that
5958 /// architecture.
6059 #[ cfg( not( armv6m) ) ]
61- pub ipr : [ RW < u8 > ; 496 ] ,
60+ ipr : [ u32 ; 124 ] ,
6261
6362 /// Interrupt Priority
6463 ///
@@ -72,14 +71,27 @@ pub struct RegisterBlock {
7271 /// so convenient byte-sized representation wouldn't work on that
7372 /// architecture.
7473 #[ cfg( armv6m) ]
75- pub ipr : [ RW < u32 > ; 8 ] ,
74+ ipr : [ u32 ; 8 ] ,
7675
7776 #[ cfg( not( armv6m) ) ]
7877 _reserved8 : [ u32 ; 580 ] ,
7978
8079 /// Software Trigger Interrupt
8180 #[ cfg( not( armv6m) ) ]
82- pub stir : WO < u32 > ,
81+ stir : u32 ,
82+ }
83+
84+ impl RegisterBlock {
85+ /// Creates a new instance of the NVIC register block.
86+ ///
87+ /// # Safety
88+ ///
89+ /// This potentially allows to create multiple instances of the NVIC register block, which
90+ /// might only be valid in certain multi-core environments.
91+ #[ inline]
92+ pub const unsafe fn new_mmio_fixed ( ) -> MmioRegisterBlock < ' static > {
93+ unsafe { RegisterBlock :: new_mmio_at ( BASE_ADDRESS ) }
94+ }
8395}
8496
8597impl NVIC {
@@ -100,9 +112,7 @@ impl NVIC {
100112 {
101113 let nr = interrupt. number ( ) ;
102114
103- unsafe {
104- self . stir . write ( u32:: from ( nr) ) ;
105- }
115+ self . write_stir ( u32:: from ( nr) ) ;
106116 }
107117
108118 /// Disables `interrupt`
@@ -113,7 +123,9 @@ impl NVIC {
113123 {
114124 let nr = interrupt. number ( ) ;
115125 // NOTE(unsafe) this is a write to a stateless register
116- unsafe { ( * Self :: PTR ) . icer [ usize:: from ( nr / 32 ) ] . write ( 1 << ( nr % 32 ) ) }
126+ let mut nvic = unsafe { Self :: steal ( ) } ;
127+ nvic. write_icer ( usize:: from ( nr / 32 ) , 1 << ( nr % 32 ) )
128+ . expect ( "invalid interrupt number" ) ;
117129 }
118130
119131 /// Enables `interrupt`
@@ -124,11 +136,11 @@ impl NVIC {
124136 where
125137 I : InterruptNumber ,
126138 {
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- }
139+ let nr = interrupt . number ( ) ;
140+ // NOTE(ptr) this is a write to a stateless register
141+ let mut nvic = unsafe { Self :: steal ( ) } ;
142+ nvic . write_iser ( usize:: from ( nr / 32 ) , 1 << ( nr % 32 ) )
143+ . expect ( "invalid interrupt number" ) ;
132144 }
133145
134146 /// Returns the NVIC priority of `interrupt`
@@ -144,16 +156,25 @@ impl NVIC {
144156 #[ cfg( not( armv6m) ) ]
145157 {
146158 let nr = interrupt. number ( ) ;
147- // NOTE(unsafe) atomic read with no side effects
148- unsafe { ( * Self :: PTR ) . ipr [ usize:: from ( nr) ] . read ( ) }
159+ // note(unsafe) atomic read with no side effects
160+ let nvic = unsafe { Self :: steal ( ) } ;
161+ let ipr_ptr = nvic. pointer_to_ipr_start ( ) as * const u8 ;
162+ // This should never happen for correct `InterruptNumber` implementations.
163+ if nr >= 124 {
164+ panic ! ( "unexpected interrupt number" ) ;
165+ }
166+ // note(unsafe) atomic read with no side effects
167+ unsafe { core:: ptr:: read_volatile ( ipr_ptr. offset ( nr as isize ) ) }
149168 }
150169
151170 #[ cfg( armv6m) ]
152171 {
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
172+ // note(unsafe) atomic read with no side effects
173+ let nvic = unsafe { Self :: steal ( ) } ;
174+ let ipr_n = nvic
175+ . read_ipr ( Self :: ipr_index ( interrupt) )
176+ . expect ( "unexpected interrupt number" ) ;
177+ ( ( ipr_n >> Self :: ipr_shift ( interrupt) ) & 0x0000_00ff ) as u8
157178 }
158179 }
159180
@@ -167,8 +188,12 @@ impl NVIC {
167188 let nr = interrupt. number ( ) ;
168189 let mask = 1 << ( nr % 32 ) ;
169190
170- // NOTE(unsafe) atomic read with no side effects
171- unsafe { ( ( * Self :: PTR ) . iabr [ usize:: from ( nr / 32 ) ] . read ( ) & mask) == mask }
191+ // note(unsafe) atomic read with no side effects
192+ let nvic = unsafe { Self :: steal ( ) } ;
193+ nvic. read_iabr ( usize:: from ( nr / 32 ) )
194+ . expect ( "unexpected interrupt number" )
195+ & mask
196+ == mask
172197 }
173198
174199 /// Checks if `interrupt` is enabled
@@ -180,8 +205,12 @@ impl NVIC {
180205 let nr = interrupt. number ( ) ;
181206 let mask = 1 << ( nr % 32 ) ;
182207
183- // NOTE(unsafe) atomic read with no side effects
184- unsafe { ( ( * Self :: PTR ) . iser [ usize:: from ( nr / 32 ) ] . read ( ) & mask) == mask }
208+ // note(unsafe) atomic read with no side effects
209+ let nvic = unsafe { Self :: steal ( ) } ;
210+ nvic. read_iser ( usize:: from ( nr / 32 ) )
211+ . expect ( "unexpected interrupt number" )
212+ & mask
213+ == mask
185214 }
186215
187216 /// Checks if `interrupt` is pending
@@ -193,8 +222,12 @@ impl NVIC {
193222 let nr = interrupt. number ( ) ;
194223 let mask = 1 << ( nr % 32 ) ;
195224
196- // NOTE(unsafe) atomic read with no side effects
197- unsafe { ( ( * Self :: PTR ) . ispr [ usize:: from ( nr / 32 ) ] . read ( ) & mask) == mask }
225+ // note(unsafe) atomic read with no side effects
226+ let nvic = unsafe { Self :: steal ( ) } ;
227+ nvic. read_ispr ( usize:: from ( nr / 32 ) )
228+ . expect ( "unexpected interrupt number" )
229+ & mask
230+ == mask
198231 }
199232
200233 /// Forces `interrupt` into pending state
@@ -206,7 +239,9 @@ impl NVIC {
206239 let nr = interrupt. number ( ) ;
207240
208241 // NOTE(unsafe) atomic stateless write; ICPR doesn't store any state
209- unsafe { ( * Self :: PTR ) . ispr [ usize:: from ( nr / 32 ) ] . write ( 1 << ( nr % 32 ) ) }
242+ let mut nvic = unsafe { Self :: steal ( ) } ;
243+ nvic. write_ispr ( usize:: from ( nr / 32 ) , 1 << ( nr % 32 ) )
244+ . expect ( "unexpected interrupt number" )
210245 }
211246
212247 /// Sets the "priority" of `interrupt` to `prio`
@@ -226,22 +261,31 @@ impl NVIC {
226261 where
227262 I : InterruptNumber ,
228263 {
229- unsafe {
230- #[ cfg( not( armv6m) ) ]
231- {
232- let nr = interrupt. number ( ) ;
233- self . ipr [ usize:: from ( nr) ] . write ( prio)
264+ #[ cfg( not( armv6m) ) ]
265+ {
266+ let nr = interrupt. number ( ) ;
267+ // NOTE(unsafe) atomic stateless write; IPR doesn't store any state
268+ let nvic = unsafe { Self :: steal ( ) } ;
269+ let ipr_ptr = nvic. pointer_to_ipr_start ( ) as * mut u8 ;
270+ // This should never happen for correct `InterruptNumber` implementations.
271+ if nr >= 124 {
272+ panic ! ( "unexpected interrupt number" ) ;
234273 }
274+ // NOTE(unsafe) atomic stateless write; IPR doesn't store any state
275+ unsafe { core:: ptr:: write_volatile ( ipr_ptr. offset ( nr as isize ) , prio) }
276+ }
235277
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- }
278+ #[ cfg( armv6m) ]
279+ {
280+ // NOTE(unsafe) atomic stateless write; IPR doesn't store any state
281+ let mut nvic = unsafe { Self :: steal ( ) } ;
282+ nvic. modify_ipr ( Self :: ipr_index ( interrupt) , |mut value| {
283+ let mask = 0x0000_00ff << Self :: ipr_shift ( interrupt) ;
284+ let prio = u32:: from ( prio) << Self :: ipr_shift ( interrupt) ;
285+
286+ ( value & !mask) | prio
287+ } )
288+ . expect ( "unexpected interrupt number" ) ;
245289 }
246290 }
247291
@@ -254,7 +298,9 @@ impl NVIC {
254298 let nr = interrupt. number ( ) ;
255299
256300 // NOTE(unsafe) atomic stateless write; ICPR doesn't store any state
257- unsafe { ( * Self :: PTR ) . icpr [ usize:: from ( nr / 32 ) ] . write ( 1 << ( nr % 32 ) ) }
301+ let mut nvic = unsafe { Self :: steal ( ) } ;
302+ nvic. write_icpr ( usize:: from ( nr / 32 ) , 1 << ( nr % 32 ) )
303+ . expect ( "unexpected interrupt number" )
258304 }
259305
260306 #[ cfg( armv6m) ]
0 commit comments