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 {
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_select! {
365 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 }
377 esp32s2 => {
378 pub(crate) const EDGE_INTERRUPTS: [Interrupt; 11] = [
379 Interrupt::TG0_T0_EDGE,
380 Interrupt::TG0_T1_EDGE,
381 Interrupt::TG0_WDT_EDGE,
382 Interrupt::TG0_LACT_EDGE,
383 Interrupt::TG1_T0_EDGE,
384 Interrupt::TG1_T1_EDGE,
385 Interrupt::TG1_WDT_EDGE,
386 Interrupt::TG1_LACT_EDGE,
387 Interrupt::SYSTIMER_TARGET0,
388 Interrupt::SYSTIMER_TARGET1,
389 Interrupt::SYSTIMER_TARGET2,
390 ];
391 }
392 esp32s3 => {
393 pub(crate) const EDGE_INTERRUPTS: [Interrupt; 0] = [];
394 }
395 _ => {
396 compile_error!("Unsupported chip");
397 }
398}
399
400#[cfg(any(feature = "rt", all(feature = "unstable", multi_core)))]
406pub(crate) unsafe fn init_vectoring() {
407 for cpu_int in [
410 CpuInterrupt::Interrupt10EdgePriority1,
411 CpuInterrupt::Interrupt22EdgePriority3,
412 CpuInterrupt::Interrupt1LevelPriority1,
413 CpuInterrupt::Interrupt19LevelPriority2,
414 CpuInterrupt::Interrupt23LevelPriority3,
415 ] {
416 cpu_int.enable();
417 }
418}
419
420#[cfg(feature = "rt")]
421pub(crate) mod rt {
422 use procmacros::ram;
423 use xtensa_lx_rt::{exception::Context, interrupt::CpuInterruptLevel};
424
425 use super::*;
426 use crate::{interrupt::InterruptStatus, system::Cpu};
427
428 #[cfg_attr(place_switch_tables_in_ram, ram)]
429 pub(crate) static CPU_INTERRUPT_INTERNAL: u32 = 0b_0010_0000_0000_0001_1000_1000_1100_0000;
430 #[cfg_attr(place_switch_tables_in_ram, ram)]
431 pub(crate) static CPU_INTERRUPT_EDGE: u32 = 0b_0111_0000_0100_0000_0000_1100_1000_0000;
432
433 #[cfg_attr(place_switch_tables_in_ram, ram)]
434 pub(crate) static CPU_INTERRUPT_LEVELS: [u32; 8] = [
435 0, CpuInterruptLevel::Level1.mask(),
437 CpuInterruptLevel::Level2.mask(),
438 CpuInterruptLevel::Level3.mask(),
439 CpuInterruptLevel::Level4.mask(),
440 CpuInterruptLevel::Level5.mask(),
441 CpuInterruptLevel::Level6.mask(),
442 CpuInterruptLevel::Level7.mask(),
443 ];
444
445 #[cfg_attr(place_switch_tables_in_ram, ram)]
448 pub static INTERRUPT_EDGE: InterruptStatus = const {
449 let mut masks = [0; crate::interrupt::STATUS_WORDS];
450
451 let mut idx = 0;
452 while idx < EDGE_INTERRUPTS.len() {
453 let interrupt_idx = EDGE_INTERRUPTS[idx] as usize;
454 let word_idx = interrupt_idx / 32;
455 masks[word_idx] |= 1 << (interrupt_idx % 32);
456 idx += 1;
457 }
458
459 InterruptStatus { status: masks }
460 };
461
462 #[unsafe(no_mangle)]
463 #[ram]
464 unsafe fn __level_1_interrupt(save_frame: &mut Context) {
465 unsafe {
466 handle_interrupts::<1>(save_frame);
467 }
468 }
469
470 #[unsafe(no_mangle)]
471 #[ram]
472 unsafe fn __level_2_interrupt(save_frame: &mut Context) {
473 unsafe {
474 handle_interrupts::<2>(save_frame);
475 }
476 }
477
478 #[unsafe(no_mangle)]
479 #[ram]
480 unsafe fn __level_3_interrupt(save_frame: &mut Context) {
481 unsafe {
482 handle_interrupts::<3>(save_frame);
483 }
484 }
485
486 #[inline(always)]
487 unsafe fn handle_interrupts<const LEVEL: u32>(save_frame: &mut Context) {
488 let cpu_interrupt_mask = xtensa_lx::interrupt::get()
489 & xtensa_lx::interrupt::get_mask()
490 & CPU_INTERRUPT_LEVELS[LEVEL as usize];
491
492 if cpu_interrupt_mask & CPU_INTERRUPT_INTERNAL != 0 {
493 let cpu_interrupt_mask = cpu_interrupt_mask & CPU_INTERRUPT_INTERNAL;
498
499 let cpu_interrupt_nr = cpu_interrupt_mask.trailing_zeros();
501
502 if ((1 << cpu_interrupt_nr) & CPU_INTERRUPT_EDGE) != 0 {
505 unsafe {
506 xtensa_lx::interrupt::clear(1 << cpu_interrupt_nr);
507 }
508 }
509
510 if let Some(handler) = cpu_interrupt_nr_to_cpu_interrupt_handler(cpu_interrupt_nr) {
511 unsafe { handler(save_frame) };
512 }
513 } else {
514 let status = if !cfg!(esp32s3) && (cpu_interrupt_mask & CPU_INTERRUPT_EDGE) != 0 {
515 unsafe { xtensa_lx::interrupt::clear(cpu_interrupt_mask & CPU_INTERRUPT_EDGE) };
521
522 INTERRUPT_EDGE
525 } else {
526 InterruptStatus::current()
529 };
530
531 let core = Cpu::current();
532 for interrupt_nr in status.iterator().filter(|&interrupt_nr| {
533 crate::interrupt::should_handle(core, interrupt_nr as u32, LEVEL)
534 }) {
535 let handler = unsafe { crate::pac::__INTERRUPTS[interrupt_nr as usize]._handler };
536 let handler: fn(&mut Context) = unsafe {
537 core::mem::transmute::<unsafe extern "C" fn(), fn(&mut Context)>(handler)
538 };
539 handler(save_frame);
540 }
541 }
542 }
543
544 #[inline]
545 pub(crate) fn cpu_interrupt_nr_to_cpu_interrupt_handler(
546 number: u32,
547 ) -> Option<unsafe extern "C" fn(save_frame: &mut Context)> {
548 use xtensa_lx_rt::*;
549 Some(match number {
551 6 => Timer0,
552 7 => Software0,
553 11 => Profiling,
554 14 => NMI,
555 15 => Timer1,
556 16 => Timer2,
557 29 => Software1,
558 _ => return None,
559 })
560 }
561
562 unsafe extern "C" {
564 fn level4_interrupt(save_frame: &mut Context);
565 fn level5_interrupt(save_frame: &mut Context);
566 #[cfg(not(all(feature = "rt", feature = "exception-handler", stack_guard_monitoring)))]
567 fn level6_interrupt(save_frame: &mut Context);
568 fn level7_interrupt(save_frame: &mut Context);
569 }
570
571 #[unsafe(no_mangle)]
572 #[ram]
573 unsafe fn __level_4_interrupt(save_frame: &mut Context) {
574 unsafe { level4_interrupt(save_frame) }
575 }
576
577 #[unsafe(no_mangle)]
578 #[ram]
579 unsafe fn __level_5_interrupt(save_frame: &mut Context) {
580 unsafe { level5_interrupt(save_frame) }
581 }
582
583 #[unsafe(no_mangle)]
584 #[ram]
585 unsafe fn __level_6_interrupt(save_frame: &mut Context) {
586 cfg_select! {
587 all(feature = "rt", feature = "exception-handler", stack_guard_monitoring) => {
588 crate::exception_handler::breakpoint_interrupt(save_frame);
589 }
590 _ => unsafe { level6_interrupt(save_frame) },
591 }
592 }
593
594 #[unsafe(no_mangle)]
595 #[ram]
596 unsafe fn __level_7_interrupt(save_frame: &mut Context) {
597 unsafe { level7_interrupt(save_frame) }
598 }
599}