cortexm/
nvic.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Cortex-M NVIC
6//!
7//! Most NVIC configuration is in the NVIC registers:
8//! <https://developer.arm.com/docs/100165/0201/nested-vectored-interrupt-controller/nvic-programmers-model/table-of-nvic-registers>
9//!
10//! Also part of the NVIC conceptually is the ICTR, which in older versions of
11//! the ARM ARM was listed in the "Summary of system control and ID registers
12//! not in the SCB" and newer ARM ARMs just file it in its own little private
13//! sub-section with the NVIC documentation. Seems a configuration register
14//! without a home, so we include it in the NVIC files as it's conceptually here.
15//! <https://developer.arm.com/docs/ddi0337/latest/nested-vectored-interrupt-controller/nvic-programmers-model/interrupt-controller-type-register-ictr>
16
17use kernel::utilities::registers::interfaces::{Readable, Writeable};
18use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
19use kernel::utilities::StaticRef;
20
21/// Generates the (u128, u128) tuple used for the NVIC's mask functions
22/// `next_pending_with_mask` and `next_pending_with_mask`.
23///
24/// if let Some(interrupt) =
25///     cortexm0p::nvic::next_pending_with_mask(interrupt_mask!(interrupts::SIO_IRQ_PROC1))
26/// {
27///     // ...
28/// }
29#[macro_export]
30macro_rules! interrupt_mask {
31    ($($interrupt: expr),+) => {{
32        let mut high_interrupt: u128 = 0;
33        let mut low_interrupt: u128 = 0;
34        $(
35            // Validate that the interrupt index is within the high and low
36            // interrupt range.
37            const{ assert!($interrupt < 256); }
38            const{ assert!($interrupt >= 0); }
39
40            if ($interrupt < 128) {
41                low_interrupt |= (1u128 << $interrupt)
42            }
43            else
44            {
45                high_interrupt |= (1u128 << ($interrupt-128))
46            }
47        );+
48        (high_interrupt, low_interrupt)
49    }};
50}
51
52register_structs! {
53    /// NVIC Registers.
54    ///
55    /// Note this generic interface exposes all possible NVICs. Most cores will
56    /// not implement all NVIC_XXXX registers. If you need to find the number
57    /// of NVICs dynamically, consult `ICTR.INTLINESNUM`.
58    NvicRegisters {
59        (0x000 => _reserved0),
60
61        /// Interrupt Controller Type Register
62        (0x004 => ictr: ReadOnly<u32, InterruptControllerType::Register>),
63
64        (0x008 => _reserved1),
65
66        /// Interrupt Set-Enable Registers
67        (0x100 => iser: [ReadWrite<u32, NvicSetClear::Register>; 32]),
68
69        /// Interrupt Clear-Enable Registers
70        (0x180 => icer: [ReadWrite<u32, NvicSetClear::Register>; 32]),
71
72        /// Interrupt Set-Pending Registers
73        (0x200 => ispr: [ReadWrite<u32, NvicSetClear::Register>; 32]),
74
75        /// Interrupt Clear-Pending Registers
76        (0x280 => icpr: [ReadWrite<u32, NvicSetClear::Register>; 32]),
77
78        /// Interrupt Active Bit Registers
79        (0x300 => iabr: [ReadWrite<u32, NvicSetClear::Register>; 32]),
80
81        (0x380 => _reserved2),
82
83        /// Interrupt Priority Registers
84        (0x400 => ipr: [ReadWrite<u32, NvicInterruptPriority::Register>; 252]),
85
86        (0x7f0 => @END),
87    }
88}
89
90register_bitfields![u32,
91    InterruptControllerType [
92        /// Total number of interrupt lines in groups of 32
93        INTLINESNUM     OFFSET(0)   NUMBITS(4)
94    ],
95
96    NvicSetClear [
97        /// For register NVIC_XXXXn, access interrupt (m+(32*n)).
98        ///  - m takes the values from 31 to 0, except for NVIC_XXXX15, where:
99        ///     - m takes the values from 15 to 0
100        ///     - register bits[31:16] are reserved, RAZ/WI
101        BITS            OFFSET(0)   NUMBITS(32)
102    ],
103
104    NvicInterruptPriority [
105        /// For register NVIC_IPRn, priority of interrupt number 4n+3.
106        PRI_N3          OFFSET(24)  NUMBITS(8),
107
108        /// For register NVIC_IPRn, priority of interrupt number 4n+2.
109        PRI_N2          OFFSET(16)  NUMBITS(8),
110
111        /// For register NVIC_IPRn, priority of interrupt number 4n+1.
112        PRI_N1          OFFSET(8)   NUMBITS(8),
113
114        /// For register NVIC_IPRn, priority of interrupt number 4n.
115        PRI_N0          OFFSET(0)   NUMBITS(8)
116    ]
117];
118
119/// The NVIC peripheral in MMIO space.
120const NVIC: StaticRef<NvicRegisters> =
121    unsafe { StaticRef::new(0xe000e000 as *const NvicRegisters) };
122
123/// Number of valid NVIC_XXXX registers. Note this is a ceiling on the number
124/// of available interrupts (as this is the number of banks of 32), but the
125/// actual number may be less. See NVIC and ICTR documentation for more detail.
126fn number_of_nvic_registers() -> usize {
127    (NVIC.ictr.read(InterruptControllerType::INTLINESNUM) + 1) as usize
128}
129
130/// Clear all pending interrupts
131pub unsafe fn clear_all_pending() {
132    for icpr in NVIC.icpr.iter().take(number_of_nvic_registers()) {
133        icpr.set(!0)
134    }
135}
136
137/// Enable all interrupts
138pub unsafe fn enable_all() {
139    for icer in NVIC.iser.iter().take(number_of_nvic_registers()) {
140        icer.set(!0)
141    }
142}
143
144/// Disable all interrupts
145pub unsafe fn disable_all() {
146    for icer in NVIC.icer.iter().take(number_of_nvic_registers()) {
147        icer.set(!0)
148    }
149}
150
151/// Get the index (0-240) the lowest number pending interrupt, or `None` if none
152/// are pending.
153pub unsafe fn next_pending() -> Option<u32> {
154    for (block, ispr) in NVIC
155        .ispr
156        .iter()
157        .take(number_of_nvic_registers())
158        .enumerate()
159    {
160        let ispr = ispr.get();
161
162        // If there are any high bits there is a pending interrupt
163        if ispr != 0 {
164            // trailing_zeros == index of first high bit
165            let bit = ispr.trailing_zeros();
166            return Some(block as u32 * 32 + bit);
167        }
168    }
169    None
170}
171
172/// Get the index (0-240) the lowest number pending interrupt while ignoring the interrupts
173/// that correspond to the bits set in mask, or `None` if none
174/// are pending.
175///
176/// Mask is defined as two u128 fields,
177///   mask.0 has the bits corresponding to interrupts from 128 to 240
178///   mask.1 has the bits corresponding to interrupts from 0 to 127
179pub unsafe fn next_pending_with_mask(mask: (u128, u128)) -> Option<u32> {
180    for (block, ispr) in NVIC
181        .ispr
182        .iter()
183        .take(number_of_nvic_registers())
184        .enumerate()
185    {
186        let interrupt_mask = if block < 4 { mask.1 } else { mask.0 };
187        let ispr_masked = ispr.get() & !((interrupt_mask >> (32 * (block % 4))) as u32);
188
189        // If there are any high bits there is a pending interrupt
190        if ispr_masked != 0 {
191            // trailing_zeros == index of first high bit
192            let bit = ispr_masked.trailing_zeros();
193            return Some(block as u32 * 32 + bit);
194        }
195    }
196    None
197}
198
199pub unsafe fn has_pending() -> bool {
200    NVIC.ispr
201        .iter()
202        .take(number_of_nvic_registers())
203        .fold(0, |i, ispr| ispr.get() | i)
204        != 0
205}
206
207/// Returns whether there are any pending interrupt bits set while ignoring
208/// the indices that correspond to the bits set in mask
209///
210/// Mask is defined as two u128 fields,
211///   mask.0 has the bits corresponding to interrupts from 128 to 240
212///   mask.1 has the bits corresponding to interrupts from 0 to 127
213pub unsafe fn has_pending_with_mask(mask: (u128, u128)) -> bool {
214    NVIC.ispr
215        .iter()
216        .take(number_of_nvic_registers())
217        .enumerate()
218        .fold(0, |i, (block, ispr)| {
219            let interrupt_mask = if block < 4 { mask.1 } else { mask.0 };
220            (ispr.get() & !((interrupt_mask >> (32 * (block % 4))) as u32)) | i
221        })
222        != 0
223}
224
225/// An opaque wrapper for a single NVIC interrupt.
226///
227/// Hand these out to low-level driver to let them control their own interrupts
228/// but not others.
229pub struct Nvic(u32);
230
231impl Nvic {
232    /// Creates a new `Nvic`
233    ///
234    /// Marked unsafe because only chip/platform configuration code should be
235    /// able to create these.
236    pub const unsafe fn new(idx: u32) -> Nvic {
237        Nvic(idx)
238    }
239
240    /// Enable the interrupt
241    pub fn enable(&self) {
242        let idx = self.0 as usize;
243
244        NVIC.iser[idx / 32].set(1 << (self.0 & 31));
245    }
246
247    /// Disable the interrupt
248    pub fn disable(&self) {
249        let idx = self.0 as usize;
250
251        NVIC.icer[idx / 32].set(1 << (self.0 & 31));
252    }
253
254    /// Clear pending state
255    pub fn clear_pending(&self) {
256        let idx = self.0 as usize;
257
258        NVIC.icpr[idx / 32].set(1 << (self.0 & 31));
259    }
260}