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