1#[cfg(esp32)]
4pub(crate) use xtensa_lx::interrupt::free;
5
6use crate::{
7 interrupt::{PriorityError, RunLevel},
8 peripherals::Interrupt,
9};
10
11#[derive(Debug, Copy, Clone)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17#[repr(u32)]
18#[instability::unstable]
19pub enum CpuInterrupt {
20 Interrupt0LevelPriority1 = 0,
22 Interrupt1LevelPriority1 = 1,
24 Interrupt2LevelPriority1 = 2,
26 Interrupt3LevelPriority1 = 3,
28 Interrupt4LevelPriority1 = 4,
30 Interrupt5LevelPriority1 = 5,
32 Interrupt6Timer0Priority1 = 6,
34 Interrupt7SoftwarePriority1 = 7,
36 Interrupt8LevelPriority1 = 8,
38 Interrupt9LevelPriority1 = 9,
40 Interrupt10EdgePriority1 = 10,
42 Interrupt11ProfilingPriority3 = 11,
44 Interrupt12LevelPriority1 = 12,
46 Interrupt13LevelPriority1 = 13,
48 Interrupt15Timer1Priority3 = 15,
50 Interrupt17LevelPriority1 = 17,
52 Interrupt18LevelPriority1 = 18,
54 Interrupt19LevelPriority2 = 19,
56 Interrupt20LevelPriority2 = 20,
58 Interrupt21LevelPriority2 = 21,
60 Interrupt22EdgePriority3 = 22,
62 Interrupt23LevelPriority3 = 23,
64 Interrupt27LevelPriority3 = 27,
66 Interrupt29SoftwarePriority3 = 29,
68 }
70
71impl CpuInterrupt {
72 #[cfg(feature = "rt")]
73 pub(super) fn from_u32(n: u32) -> Option<Self> {
74 match n {
75 0 => Some(Self::Interrupt0LevelPriority1),
76 1 => Some(Self::Interrupt1LevelPriority1),
77 2 => Some(Self::Interrupt2LevelPriority1),
78 3 => Some(Self::Interrupt3LevelPriority1),
79 4 => Some(Self::Interrupt4LevelPriority1),
80 5 => Some(Self::Interrupt5LevelPriority1),
81 6 => Some(Self::Interrupt6Timer0Priority1),
82 7 => Some(Self::Interrupt7SoftwarePriority1),
83 8 => Some(Self::Interrupt8LevelPriority1),
84 9 => Some(Self::Interrupt9LevelPriority1),
85 10 => Some(Self::Interrupt10EdgePriority1),
86 11 => Some(Self::Interrupt11ProfilingPriority3),
87 12 => Some(Self::Interrupt12LevelPriority1),
88 13 => Some(Self::Interrupt13LevelPriority1),
89 15 => Some(Self::Interrupt15Timer1Priority3),
90 17 => Some(Self::Interrupt17LevelPriority1),
91 18 => Some(Self::Interrupt18LevelPriority1),
92 19 => Some(Self::Interrupt19LevelPriority2),
93 20 => Some(Self::Interrupt20LevelPriority2),
94 21 => Some(Self::Interrupt21LevelPriority2),
95 22 => Some(Self::Interrupt22EdgePriority3),
96 23 => Some(Self::Interrupt23LevelPriority3),
97 27 => Some(Self::Interrupt27LevelPriority3),
98 29 => Some(Self::Interrupt29SoftwarePriority3),
99 _ => None,
100 }
101 }
102
103 #[inline]
104 #[cfg(feature = "rt")]
105 pub(crate) fn is_vectored(self) -> bool {
106 true
108 }
109
110 #[inline]
112 #[instability::unstable]
113 pub fn enable(self) {
114 enable_cpu_interrupt_raw(self as u32);
115 }
116
117 #[inline]
119 #[instability::unstable]
120 pub fn clear(self) {
121 unsafe { xtensa_lx::interrupt::clear(1 << self as u32) };
122 }
123
124 #[inline]
126 #[instability::unstable]
127 pub fn priority(self) -> Priority {
128 match self {
129 CpuInterrupt::Interrupt0LevelPriority1
130 | CpuInterrupt::Interrupt1LevelPriority1
131 | CpuInterrupt::Interrupt2LevelPriority1
132 | CpuInterrupt::Interrupt3LevelPriority1
133 | CpuInterrupt::Interrupt4LevelPriority1
134 | CpuInterrupt::Interrupt5LevelPriority1
135 | CpuInterrupt::Interrupt6Timer0Priority1
136 | CpuInterrupt::Interrupt7SoftwarePriority1
137 | CpuInterrupt::Interrupt8LevelPriority1
138 | CpuInterrupt::Interrupt9LevelPriority1
139 | CpuInterrupt::Interrupt10EdgePriority1
140 | CpuInterrupt::Interrupt12LevelPriority1
141 | CpuInterrupt::Interrupt13LevelPriority1
142 | CpuInterrupt::Interrupt17LevelPriority1
143 | CpuInterrupt::Interrupt18LevelPriority1 => Priority::Priority1,
144
145 CpuInterrupt::Interrupt19LevelPriority2
146 | CpuInterrupt::Interrupt20LevelPriority2
147 | CpuInterrupt::Interrupt21LevelPriority2 => Priority::Priority2,
148
149 CpuInterrupt::Interrupt11ProfilingPriority3
150 | CpuInterrupt::Interrupt15Timer1Priority3
151 | CpuInterrupt::Interrupt22EdgePriority3
152 | CpuInterrupt::Interrupt27LevelPriority3
153 | CpuInterrupt::Interrupt29SoftwarePriority3
154 | CpuInterrupt::Interrupt23LevelPriority3 => Priority::Priority3,
155 }
156 }
157
158 #[inline]
159 #[cfg(feature = "rt")]
160 pub(crate) fn level(self) -> u32 {
161 self.priority() as u32
162 }
163}
164
165#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
170#[cfg_attr(feature = "defmt", derive(defmt::Format))]
171#[repr(u8)]
172#[non_exhaustive]
173pub enum Priority {
174 Priority1 = 1,
176 Priority2 = 2,
178 Priority3 = 3,
180 }
183
184impl Priority {
185 #[instability::unstable]
187 pub const fn max() -> Priority {
188 Priority::Priority3
189 }
190
191 pub const fn min() -> Priority {
193 Priority::Priority1
194 }
195}
196
197#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
199#[cfg_attr(feature = "defmt", derive(defmt::Format))]
200#[repr(u8)]
201#[non_exhaustive]
202pub enum ElevatedRunLevel {
203 Level1 = 1,
205 Level2 = 2,
207 Level3 = 3,
209 Level4 = 4,
211 Level5 = 5,
213 Level6 = 6,
215 Level7 = 7,
217}
218
219impl ElevatedRunLevel {
220 #[instability::unstable]
222 pub const fn max() -> ElevatedRunLevel {
223 ElevatedRunLevel::Level7
224 }
225
226 pub const fn min() -> ElevatedRunLevel {
228 ElevatedRunLevel::Level1
229 }
230
231 pub(crate) fn try_from_u32(priority: u32) -> Result<Self, PriorityError> {
232 match priority {
233 1 => Ok(ElevatedRunLevel::Level1),
234 2 => Ok(ElevatedRunLevel::Level2),
235 3 => Ok(ElevatedRunLevel::Level3),
236 4 => Ok(ElevatedRunLevel::Level4),
237 5 => Ok(ElevatedRunLevel::Level5),
238 6 => Ok(ElevatedRunLevel::Level6),
239 7 => Ok(ElevatedRunLevel::Level7),
240
241 _ => Err(PriorityError::InvalidInterruptPriority),
242 }
243 }
244
245 pub const fn from_priority(priority: Priority) -> Self {
247 match priority {
248 Priority::Priority1 => ElevatedRunLevel::Level1,
249 Priority::Priority2 => ElevatedRunLevel::Level2,
250 Priority::Priority3 => ElevatedRunLevel::Level3,
251 }
252 }
253}
254
255impl From<Priority> for ElevatedRunLevel {
256 fn from(priority: Priority) -> Self {
257 Self::from_priority(priority)
258 }
259}
260
261#[instability::unstable]
262impl TryFrom<u32> for ElevatedRunLevel {
263 type Error = PriorityError;
264
265 fn try_from(value: u32) -> Result<Self, Self::Error> {
266 Self::try_from_u32(value)
267 }
268}
269
270#[instability::unstable]
271impl TryFrom<u8> for ElevatedRunLevel {
272 type Error = PriorityError;
273
274 fn try_from(value: u8) -> Result<Self, Self::Error> {
275 Self::try_from(value as u32)
276 }
277}
278
279pub(super) const DISABLED_CPU_INTERRUPT: u32 = 16;
280
281pub(crate) fn enable_cpu_interrupt_raw(cpu_interrupt: u32) {
285 unsafe { xtensa_lx::interrupt::enable_mask(1 << cpu_interrupt) };
286}
287
288pub(crate) fn current_raw_runlevel() -> u32 {
292 xtensa_lx::interrupt::get_level()
293}
294
295pub(crate) unsafe fn change_current_runlevel(level: RunLevel) -> RunLevel {
304 let token: u32;
305 unsafe {
306 match level {
307 RunLevel::ThreadMode => core::arch::asm!("rsil {0}, 0", out(reg) token),
308 RunLevel::Interrupt(ElevatedRunLevel::Level1) => {
309 core::arch::asm!("rsil {0}, 1", out(reg) token)
310 }
311 RunLevel::Interrupt(ElevatedRunLevel::Level2) => {
312 core::arch::asm!("rsil {0}, 2", out(reg) token)
313 }
314 RunLevel::Interrupt(ElevatedRunLevel::Level3) => {
315 core::arch::asm!("rsil {0}, 3", out(reg) token)
316 }
317 RunLevel::Interrupt(ElevatedRunLevel::Level4) => {
318 core::arch::asm!("rsil {0}, 4", out(reg) token)
319 }
320 RunLevel::Interrupt(ElevatedRunLevel::Level5) => {
321 core::arch::asm!("rsil {0}, 5", out(reg) token)
322 }
323 RunLevel::Interrupt(ElevatedRunLevel::Level6) => {
324 core::arch::asm!("rsil {0}, 6", out(reg) token)
325 }
326 RunLevel::Interrupt(ElevatedRunLevel::Level7) => {
327 core::arch::asm!("rsil {0}, 7", out(reg) token)
328 }
329 };
330 }
331
332 unwrap!(RunLevel::try_from_u32(token & 0x0F))
333}
334
335#[inline(always)]
341#[instability::unstable]
342pub fn wait_for_interrupt() {
343 unsafe { core::arch::asm!("waiti 0") };
344}
345
346pub(crate) fn priority_to_cpu_interrupt(interrupt: Interrupt, level: Priority) -> CpuInterrupt {
347 if EDGE_INTERRUPTS.contains(&interrupt) {
348 match level {
349 Priority::Priority1 => CpuInterrupt::Interrupt10EdgePriority1,
350 Priority::Priority2 => {
351 warn!("Priority 2 edge interrupts are not supported, using Priority 1 instead");
352 CpuInterrupt::Interrupt10EdgePriority1
353 }
354 Priority::Priority3 => CpuInterrupt::Interrupt22EdgePriority3,
355 }
356 } else {
357 match level {
358 Priority::Priority1 => CpuInterrupt::Interrupt1LevelPriority1,
359 Priority::Priority2 => CpuInterrupt::Interrupt19LevelPriority2,
360 Priority::Priority3 => CpuInterrupt::Interrupt23LevelPriority3,
361 }
362 }
363}
364
365cfg_select! {
366 esp32 => {
367 pub(crate) const EDGE_INTERRUPTS: [Interrupt; 8] = [
368 Interrupt::TG0_T0_EDGE,
369 Interrupt::TG0_T1_EDGE,
370 Interrupt::TG0_WDT_EDGE,
371 Interrupt::TG0_LACT_EDGE,
372 Interrupt::TG1_T0_EDGE,
373 Interrupt::TG1_T1_EDGE,
374 Interrupt::TG1_WDT_EDGE,
375 Interrupt::TG1_LACT_EDGE,
376 ];
377 }
378 esp32s2 => {
379 pub(crate) const EDGE_INTERRUPTS: [Interrupt; 11] = [
380 Interrupt::TG0_T0_EDGE,
381 Interrupt::TG0_T1_EDGE,
382 Interrupt::TG0_WDT_EDGE,
383 Interrupt::TG0_LACT_EDGE,
384 Interrupt::TG1_T0_EDGE,
385 Interrupt::TG1_T1_EDGE,
386 Interrupt::TG1_WDT_EDGE,
387 Interrupt::TG1_LACT_EDGE,
388 Interrupt::SYSTIMER_TARGET0,
389 Interrupt::SYSTIMER_TARGET1,
390 Interrupt::SYSTIMER_TARGET2,
391 ];
392 }
393 esp32s3 => {
394 pub(crate) const EDGE_INTERRUPTS: [Interrupt; 0] = [];
395 }
396 _ => {
397 compile_error!("Unsupported chip");
398 }
399}
400
401#[cfg(any(feature = "rt", all(feature = "unstable", multi_core)))]
407pub(crate) unsafe fn init_vectoring() {
408 for cpu_int in [
411 CpuInterrupt::Interrupt10EdgePriority1,
412 CpuInterrupt::Interrupt22EdgePriority3,
413 CpuInterrupt::Interrupt1LevelPriority1,
414 CpuInterrupt::Interrupt19LevelPriority2,
415 CpuInterrupt::Interrupt23LevelPriority3,
416 ] {
417 cpu_int.enable();
418 }
419}
420
421#[cfg(feature = "rt")]
422pub(crate) mod rt {
423 use procmacros::ram;
424 use xtensa_lx_rt::{exception::Context, interrupt::CpuInterruptLevel};
425
426 use super::*;
427 use crate::{interrupt::InterruptStatus, system::Cpu};
428
429 #[cfg_attr(place_switch_tables_in_ram, ram)]
430 pub(crate) static CPU_INTERRUPT_INTERNAL: u32 = 0b_0010_0000_0000_0001_1000_1000_1100_0000;
431 #[cfg_attr(place_switch_tables_in_ram, ram)]
432 pub(crate) static CPU_INTERRUPT_EDGE: u32 = 0b_0111_0000_0100_0000_0000_1100_1000_0000;
433
434 #[cfg_attr(place_switch_tables_in_ram, ram)]
435 pub(crate) static CPU_INTERRUPT_LEVELS: [u32; 8] = [
436 0, CpuInterruptLevel::Level1.mask(),
438 CpuInterruptLevel::Level2.mask(),
439 CpuInterruptLevel::Level3.mask(),
440 CpuInterruptLevel::Level4.mask(),
441 CpuInterruptLevel::Level5.mask(),
442 CpuInterruptLevel::Level6.mask(),
443 CpuInterruptLevel::Level7.mask(),
444 ];
445
446 #[cfg_attr(place_switch_tables_in_ram, ram)]
449 pub static INTERRUPT_EDGE: InterruptStatus = const {
450 let mut masks = [0; crate::interrupt::STATUS_WORDS];
451
452 let mut idx = 0;
453 while idx < EDGE_INTERRUPTS.len() {
454 let interrupt_idx = EDGE_INTERRUPTS[idx] as usize;
455 let word_idx = interrupt_idx / 32;
456 masks[word_idx] |= 1 << (interrupt_idx % 32);
457 idx += 1;
458 }
459
460 InterruptStatus { status: masks }
461 };
462
463 #[unsafe(no_mangle)]
464 #[ram]
465 unsafe fn __level_1_interrupt(save_frame: &mut Context) {
466 unsafe {
467 handle_interrupts::<1>(save_frame);
468 }
469 }
470
471 #[unsafe(no_mangle)]
472 #[ram]
473 unsafe fn __level_2_interrupt(save_frame: &mut Context) {
474 unsafe {
475 handle_interrupts::<2>(save_frame);
476 }
477 }
478
479 #[unsafe(no_mangle)]
480 #[ram]
481 unsafe fn __level_3_interrupt(save_frame: &mut Context) {
482 unsafe {
483 handle_interrupts::<3>(save_frame);
484 }
485 }
486
487 #[inline(always)]
488 unsafe fn handle_interrupts<const LEVEL: u32>(save_frame: &mut Context) {
489 let cpu_interrupt_mask = xtensa_lx::interrupt::get()
490 & xtensa_lx::interrupt::get_mask()
491 & CPU_INTERRUPT_LEVELS[LEVEL as usize];
492
493 if cpu_interrupt_mask & CPU_INTERRUPT_INTERNAL != 0 {
494 let cpu_interrupt_mask = cpu_interrupt_mask & CPU_INTERRUPT_INTERNAL;
499
500 let cpu_interrupt_nr = cpu_interrupt_mask.trailing_zeros();
502
503 if ((1 << cpu_interrupt_nr) & CPU_INTERRUPT_EDGE) != 0 {
506 unsafe {
507 xtensa_lx::interrupt::clear(1 << cpu_interrupt_nr);
508 }
509 }
510
511 if let Some(handler) = cpu_interrupt_nr_to_cpu_interrupt_handler(cpu_interrupt_nr) {
512 unsafe { handler(save_frame) };
513 }
514 } else {
515 let status = if !cfg!(esp32s3) && (cpu_interrupt_mask & CPU_INTERRUPT_EDGE) != 0 {
516 unsafe { xtensa_lx::interrupt::clear(cpu_interrupt_mask & CPU_INTERRUPT_EDGE) };
522
523 INTERRUPT_EDGE
526 } else {
527 InterruptStatus::current()
530 };
531
532 let core = Cpu::current();
533 for interrupt_nr in status.iterator().filter(|&interrupt_nr| {
534 crate::interrupt::should_handle(core, interrupt_nr as u32, LEVEL)
535 }) {
536 let handler = unsafe { crate::pac::__INTERRUPTS[interrupt_nr as usize]._handler };
537 let handler: fn(&mut Context) = unsafe {
538 core::mem::transmute::<unsafe extern "C" fn(), fn(&mut Context)>(handler)
539 };
540 handler(save_frame);
541 }
542 }
543 }
544
545 #[inline]
546 pub(crate) fn cpu_interrupt_nr_to_cpu_interrupt_handler(
547 number: u32,
548 ) -> Option<unsafe extern "C" fn(save_frame: &mut Context)> {
549 use xtensa_lx_rt::*;
550 Some(match number {
552 6 => Timer0,
553 7 => Software0,
554 11 => Profiling,
555 14 => NMI,
556 15 => Timer1,
557 16 => Timer2,
558 29 => Software1,
559 _ => return None,
560 })
561 }
562
563 unsafe extern "C" {
565 fn level4_interrupt(save_frame: &mut Context);
566 fn level5_interrupt(save_frame: &mut Context);
567 #[cfg(not(all(feature = "rt", feature = "exception-handler", stack_guard_monitoring)))]
568 fn level6_interrupt(save_frame: &mut Context);
569 fn level7_interrupt(save_frame: &mut Context);
570 }
571
572 #[unsafe(no_mangle)]
573 #[ram]
574 unsafe fn __level_4_interrupt(save_frame: &mut Context) {
575 unsafe { level4_interrupt(save_frame) }
576 }
577
578 #[unsafe(no_mangle)]
579 #[ram]
580 unsafe fn __level_5_interrupt(save_frame: &mut Context) {
581 unsafe { level5_interrupt(save_frame) }
582 }
583
584 #[unsafe(no_mangle)]
585 #[ram]
586 unsafe fn __level_6_interrupt(save_frame: &mut Context) {
587 cfg_select! {
588 all(feature = "rt", feature = "exception-handler", stack_guard_monitoring) => {
589 crate::exception_handler::breakpoint_interrupt(save_frame);
590 }
591 _ => unsafe { level6_interrupt(save_frame) },
592 }
593 }
594
595 #[unsafe(no_mangle)]
596 #[ram]
597 unsafe fn __level_7_interrupt(save_frame: &mut Context) {
598 unsafe { level7_interrupt(save_frame) }
599 }
600}