esp_riscv_rt/
lib.rs

1//! Minimal startup/runtime for RISC-V CPUs from Espressif.
2//!
3//! ## Features
4//!
5//! This crate provides:
6//!
7//! - Before main initialization of the `.bss` and `.data` sections controlled by features
8//! - `#[entry]` to declare the entry point of the program
9//!
10//! ## Feature Flags
11#![doc = document_features::document_features!()]
12#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
13#![deny(missing_docs)]
14#![no_std]
15
16use core::arch::global_asm;
17
18pub use riscv;
19use riscv::register::{
20    mcause,
21    mtvec::{self, TrapMode},
22};
23pub use riscv_rt_macros::{entry, pre_init};
24
25pub use self::Interrupt as interrupt;
26
27#[unsafe(export_name = "error: esp-riscv-rt appears more than once in the dependency graph")]
28#[doc(hidden)]
29pub static __ONCE__: () = ();
30
31unsafe extern "C" {
32    // Boundaries of the .bss section
33    static mut _bss_end: u32;
34    static mut _bss_start: u32;
35
36    // Boundaries of the .data section
37    static mut _data_end: u32;
38    static mut _data_start: u32;
39
40    // Initial values of the .data section (stored in Flash)
41    static _sidata: u32;
42}
43
44/// Rust entry point (_start_rust)
45///
46/// Zeros bss section, initializes data section and calls main. This function
47/// never returns.
48///
49/// # Safety
50///
51/// This function should not be called directly by the user, and should instead
52/// be invoked by the runtime implicitly.
53#[unsafe(link_section = ".init.rust")]
54#[unsafe(export_name = "_start_rust")]
55pub unsafe extern "C" fn start_rust(a0: usize, a1: usize, a2: usize) -> ! {
56    unsafe {
57        unsafe extern "Rust" {
58            fn hal_main(a0: usize, a1: usize, a2: usize) -> !;
59
60            fn __post_init();
61
62            fn _setup_interrupts();
63
64        }
65
66        __post_init();
67
68        _setup_interrupts();
69
70        hal_main(a0, a1, a2);
71    }
72}
73
74/// Registers saved in trap handler
75#[derive(Debug, Default, Clone, Copy)]
76#[repr(C)]
77pub struct TrapFrame {
78    /// Return address, stores the address to return to after a function call or
79    /// interrupt.
80    pub ra: usize,
81    /// Temporary register t0, used for intermediate values.
82    pub t0: usize,
83    /// Temporary register t1, used for intermediate values.
84    pub t1: usize,
85    /// Temporary register t2, used for intermediate values.
86    pub t2: usize,
87    /// Temporary register t3, used for intermediate values.
88    pub t3: usize,
89    /// Temporary register t4, used for intermediate values.
90    pub t4: usize,
91    /// Temporary register t5, used for intermediate values.
92    pub t5: usize,
93    /// Temporary register t6, used for intermediate values.
94    pub t6: usize,
95    /// Argument register a0, typically used to pass the first argument to a
96    /// function.
97    pub a0: usize,
98    /// Argument register a1, typically used to pass the second argument to a
99    /// function.
100    pub a1: usize,
101    /// Argument register a2, typically used to pass the third argument to a
102    /// function.
103    pub a2: usize,
104    /// Argument register a3, typically used to pass the fourth argument to a
105    /// function.
106    pub a3: usize,
107    /// Argument register a4, typically used to pass the fifth argument to a
108    /// function.
109    pub a4: usize,
110    /// Argument register a5, typically used to pass the sixth argument to a
111    /// function.
112    pub a5: usize,
113    /// Argument register a6, typically used to pass the seventh argument to a
114    /// function.
115    pub a6: usize,
116    /// Argument register a7, typically used to pass the eighth argument to a
117    /// function.
118    pub a7: usize,
119    /// Saved register s0, used to hold values across function calls.
120    pub s0: usize,
121    /// Saved register s1, used to hold values across function calls.
122    pub s1: usize,
123    /// Saved register s2, used to hold values across function calls.
124    pub s2: usize,
125    /// Saved register s3, used to hold values across function calls.
126    pub s3: usize,
127    /// Saved register s4, used to hold values across function calls.
128    pub s4: usize,
129    /// Saved register s5, used to hold values across function calls.
130    pub s5: usize,
131    /// Saved register s6, used to hold values across function calls.
132    pub s6: usize,
133    /// Saved register s7, used to hold values across function calls.
134    pub s7: usize,
135    /// Saved register s8, used to hold values across function calls.
136    pub s8: usize,
137    /// Saved register s9, used to hold values across function calls.
138    pub s9: usize,
139    /// Saved register s10, used to hold values across function calls.
140    pub s10: usize,
141    /// Saved register s11, used to hold values across function calls.
142    pub s11: usize,
143    /// Global pointer register, holds the address of the global data area.
144    pub gp: usize,
145    /// Thread pointer register, holds the address of the thread-local storage
146    /// area.
147    pub tp: usize,
148    /// Stack pointer register, holds the address of the top of the stack.
149    pub sp: usize,
150    /// Program counter, stores the address of the next instruction to be
151    /// executed.
152    pub pc: usize,
153    /// Machine status register, holds the current status of the processor,
154    /// including interrupt enable bits and privilege mode.
155    pub mstatus: usize,
156    /// Machine cause register, contains the reason for the trap (e.g.,
157    /// exception or interrupt number).
158    pub mcause: usize,
159    /// Machine trap value register, contains additional information about the
160    /// trap (e.g., faulting address).
161    pub mtval: usize,
162}
163
164/// Trap entry point rust (_start_trap_rust)
165///
166/// `scause`/`mcause` is read to determine the cause of the trap. XLEN-1 bit
167/// indicates if it's an interrupt or an exception. The result is examined and
168/// ExceptionHandler or one of the core interrupt handlers is called.
169///
170/// # Safety
171///
172/// This function should not be called directly by the user, and should instead
173/// be invoked by the runtime implicitly.
174#[unsafe(link_section = ".trap.rust")]
175#[unsafe(export_name = "_start_trap_rust")]
176pub unsafe extern "C" fn start_trap_rust(trap_frame: *const TrapFrame) {
177    unsafe extern "C" {
178        fn ExceptionHandler(trap_frame: &TrapFrame);
179        fn DefaultHandler();
180    }
181
182    unsafe {
183        let cause = mcause::read();
184
185        if cause.is_exception() {
186            ExceptionHandler(&*trap_frame)
187        } else if cause.code() < __INTERRUPTS.len() {
188            let h = &__INTERRUPTS[cause.code()];
189            if h.reserved == 0 {
190                DefaultHandler();
191            } else {
192                (h.handler)();
193            }
194        } else {
195            DefaultHandler();
196        }
197    }
198}
199
200#[doc(hidden)]
201#[unsafe(no_mangle)]
202#[allow(unused_variables, non_snake_case)]
203pub fn DefaultExceptionHandler(trap_frame: &TrapFrame) -> ! {
204    loop {
205        // Prevent this from turning into a UDF instruction
206        // see rust-lang/rust#28728 for details
207        continue;
208    }
209}
210
211#[doc(hidden)]
212#[unsafe(no_mangle)]
213#[allow(unused_variables, non_snake_case)]
214pub fn DefaultInterruptHandler() {
215    loop {
216        // Prevent this from turning into a UDF instruction
217        // see rust-lang/rust#28728 for details
218        continue;
219    }
220}
221
222// Interrupts
223#[doc(hidden)]
224pub enum Interrupt {
225    UserSoft,
226    SupervisorSoft,
227    MachineSoft,
228    UserTimer,
229    SupervisorTimer,
230    MachineTimer,
231    UserExternal,
232    SupervisorExternal,
233    MachineExternal,
234}
235
236unsafe extern "C" {
237    fn UserSoft();
238    fn SupervisorSoft();
239    fn MachineSoft();
240    fn UserTimer();
241    fn SupervisorTimer();
242    fn MachineTimer();
243    fn UserExternal();
244    fn SupervisorExternal();
245    fn MachineExternal();
246}
247
248#[doc(hidden)]
249pub union Vector {
250    pub handler: unsafe extern "C" fn(),
251    pub reserved: usize,
252}
253
254#[doc(hidden)]
255#[unsafe(no_mangle)]
256pub static __INTERRUPTS: [Vector; 12] = [
257    Vector { handler: UserSoft },
258    Vector {
259        handler: SupervisorSoft,
260    },
261    Vector { reserved: 0 },
262    Vector {
263        handler: MachineSoft,
264    },
265    Vector { handler: UserTimer },
266    Vector {
267        handler: SupervisorTimer,
268    },
269    Vector { reserved: 0 },
270    Vector {
271        handler: MachineTimer,
272    },
273    Vector {
274        handler: UserExternal,
275    },
276    Vector {
277        handler: SupervisorExternal,
278    },
279    Vector { reserved: 0 },
280    Vector {
281        handler: MachineExternal,
282    },
283];
284
285#[doc(hidden)]
286#[unsafe(no_mangle)]
287#[rustfmt::skip]
288pub unsafe extern "Rust" fn default_post_init() {}
289
290/// Default implementation of `_setup_interrupts` that sets `mtvec`/`stvec` to a
291/// trap handler address.
292#[doc(hidden)]
293#[unsafe(no_mangle)]
294#[rustfmt::skip]
295pub unsafe extern "Rust" fn default_setup_interrupts() { unsafe {
296    unsafe extern "C" {
297        fn _start_trap();
298    }
299
300    mtvec::write(_start_trap as usize, TrapMode::Direct);
301}}
302
303/// Parse cfg attributes inside a global_asm call.
304macro_rules! cfg_global_asm {
305    {@inner, [$($x:tt)*], } => {
306        global_asm!{$($x)*}
307    };
308    (@inner, [$($x:tt)*], #[cfg($meta:meta)] $asm:literal, $($rest:tt)*) => {
309        #[cfg($meta)]
310        cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
311        #[cfg(not($meta))]
312        cfg_global_asm!{@inner, [$($x)*], $($rest)*}
313    };
314    {@inner, [$($x:tt)*], $asm:literal, $($rest:tt)*} => {
315        cfg_global_asm!{@inner, [$($x)* $asm,], $($rest)*}
316    };
317    {$($asms:tt)*} => {
318        cfg_global_asm!{@inner, [], $($asms)*}
319    };
320}
321
322cfg_global_asm! {
323    r#"
324/*
325    Entry point of all programs (_start).
326
327    It initializes DWARF call frame information, the stack pointer, the
328    frame pointer (needed for closures to work in start_rust) and the global
329    pointer. Then it calls _start_rust.
330*/
331
332.section .init, "ax"
333.global _start
334
335_start:
336    /* Jump to the absolute address defined by the linker script. */
337    lui ra, %hi(_abs_start)
338    jr %lo(_abs_start)(ra)
339
340_abs_start:
341    .option norelax
342    .cfi_startproc
343    .cfi_undefined ra
344"#,
345#[cfg(feature = "has-mie-mip")]
346    r#"
347    csrw mie, 0
348    csrw mip, 0
349"#,
350    r#"
351    la a0, _bss_start
352    la a1, _bss_end
353    bge a0, a1, 2f
354    mv a3, x0
355    1:
356    sw a3, 0(a0)
357    addi a0, a0, 4
358    blt a0, a1, 1b
359    2:
360"#,
361#[cfg(feature = "rtc-ram")]
362    r#"
363    la a0, _rtc_fast_bss_start
364    la a1, _rtc_fast_bss_end
365    bge a0, a1, 2f
366    mv a3, x0
367    1:
368    sw a3, 0(a0)
369    addi a0, a0, 4
370    blt a0, a1, 1b
371    2:
372"#,
373    // Zero .rtc_fast.persistent iff the chip just powered on
374#[cfg(feature = "rtc-ram")]
375    r#"
376    mv a0, zero
377    call rtc_get_reset_reason
378    addi a1, zero, 1
379    bne a0, a1, 2f
380    la a0, _rtc_fast_persistent_start
381    la a1, _rtc_fast_persistent_end
382    bge a0, a1, 2f
383    mv a3, x0
384    1:
385    sw a3, 0(a0)
386    addi a0, a0, 4
387    blt a0, a1, 1b
388    2:
389"#,
390    r#"
391    li  x1, 0
392    li  x2, 0
393    li  x3, 0
394    li  x4, 0
395    li  x5, 0
396    li  x6, 0
397    li  x7, 0
398    li  x8, 0
399    li  x9, 0
400    li  x10,0
401    li  x11,0
402    li  x12,0
403    li  x13,0
404    li  x14,0
405    li  x15,0
406    li  x16,0
407    li  x17,0
408    li  x18,0
409    li  x19,0
410    li  x20,0
411    li  x21,0
412    li  x22,0
413    li  x23,0
414    li  x24,0
415    li  x25,0
416    li  x26,0
417    li  x27,0
418    li  x28,0
419    li  x29,0
420    li  x30,0
421    li  x31,0
422
423    .option push
424    .option norelax
425    la gp, __global_pointer$
426    .option pop
427
428    // Check hart ID
429    csrr t2, mhartid
430    lui t0, %hi(_max_hart_id)
431    add t0, t0, %lo(_max_hart_id)
432    bgtu t2, t0, abort
433
434    // Allocate stack
435    la sp, _stack_start
436    li t0, 4 // make sure stack start is in RAM
437    sub sp, sp, t0
438    andi sp, sp, -16 // Force 16-byte alignment
439
440    // Set frame pointer
441    add s0, sp, zero
442
443    jal zero, _start_rust
444
445    .cfi_endproc
446
447/*
448    Trap entry points (_start_trap, _start_trapN for N in 1..=31)
449
450    The default implementation saves all registers to the stack and calls
451    _start_trap_rust, then restores all saved registers before `mret`
452*/
453.section .trap, "ax"
454.weak _start_trap  /* Exceptions call into _start_trap in vectored mode */
455.weak _start_trap1
456.weak _start_trap2
457.weak _start_trap3
458.weak _start_trap4
459.weak _start_trap5
460.weak _start_trap6
461.weak _start_trap7
462.weak _start_trap8
463.weak _start_trap9
464.weak _start_trap10
465.weak _start_trap11
466.weak _start_trap12
467.weak _start_trap13
468.weak _start_trap14
469.weak _start_trap15
470.weak _start_trap16
471.weak _start_trap17
472.weak _start_trap18
473.weak _start_trap19
474.weak _start_trap20
475.weak _start_trap21
476.weak _start_trap22
477.weak _start_trap23
478.weak _start_trap24
479.weak _start_trap25
480.weak _start_trap26
481.weak _start_trap27
482.weak _start_trap28
483.weak _start_trap29
484.weak _start_trap30
485.weak _start_trap31
486"#,
487r#"
488_start_trap: // Handle exceptions in vectored mode
489    // move SP to some save place if it's pointing below the RAM
490    // otherwise we won't be able to do anything reasonable
491    // (since we don't have a working stack)
492    //
493    // most probably we will just print something and halt in this case
494    // we actually can't do anything else
495    csrw mscratch, t0
496    la t0, _dram_origin
497    bge sp, t0, 1f
498
499    // use the reserved exception cause 14 to signal we detected a stack overflow
500    li t0, 14
501    csrw mcause, t0
502
503    // set SP to the start of the stack
504    la sp, _stack_start
505    li t0, 4 // make sure stack start is in RAM
506    sub sp, sp, t0
507    andi sp, sp, -16 // Force 16-byte alignment
508
509    1:
510    csrr t0, mscratch
511    // now SP is in RAM - continue
512
513    addi sp, sp, -40*4
514    sw ra, 0(sp)
515    la ra, _start_trap_rust_hal /* Load the HAL trap handler */
516    j _start_trap_direct
517_start_trap1:
518    addi sp, sp, -40*4
519    sw ra, 0(sp)
520    la ra, interrupt1
521    j _start_trap_direct
522_start_trap2:
523    addi sp, sp, -40*4
524    sw ra, 0(sp)
525    la ra, interrupt2
526    j _start_trap_direct
527_start_trap3:
528    addi sp, sp, -40*4
529    sw ra, 0(sp)
530    la ra, interrupt3
531    j _start_trap_direct
532_start_trap4:
533    addi sp, sp, -40*4
534    sw ra, 0(sp)
535    la ra, interrupt4
536    j _start_trap_direct
537_start_trap5:
538    addi sp, sp, -40*4
539    sw ra, 0(sp)
540    la ra, interrupt5
541    j _start_trap_direct
542_start_trap6:
543    addi sp, sp, -40*4
544    sw ra, 0(sp)
545    la ra, interrupt6
546    j _start_trap_direct
547_start_trap7:
548    addi sp, sp, -40*4
549    sw ra, 0(sp)
550    la ra, interrupt7
551    j _start_trap_direct
552_start_trap8:
553    addi sp, sp, -40*4
554    sw ra, 0(sp)
555    la ra, interrupt8
556    j _start_trap_direct
557_start_trap9:
558    addi sp, sp, -40*4
559    sw ra, 0(sp)
560    la ra, interrupt9
561    j _start_trap_direct
562_start_trap10:
563    addi sp, sp, -40*4
564    sw ra, 0(sp)
565    la ra, interrupt10
566    j _start_trap_direct
567_start_trap11:
568    addi sp, sp, -40*4
569    sw ra, 0(sp)
570    la ra, interrupt11
571    j _start_trap_direct
572_start_trap12:
573    addi sp, sp, -40*4
574    sw ra, 0(sp)
575    la ra, interrupt12
576    j _start_trap_direct
577_start_trap13:
578    addi sp, sp, -40*4
579    sw ra, 0(sp)
580    la ra, interrupt13
581    j _start_trap_direct
582_start_trap14:
583    addi sp, sp, -40*4
584    sw ra, 0(sp)
585    la ra, interrupt14
586    j _start_trap_direct
587_start_trap15:
588    addi sp, sp, -40*4
589    sw ra, 0(sp)
590    la ra, interrupt15
591    j _start_trap_direct
592_start_trap16:
593    addi sp, sp, -40*4
594    sw ra, 0(sp)
595    la ra, interrupt16
596    j _start_trap_direct
597_start_trap17:
598    addi sp, sp, -40*4
599    sw ra, 0(sp)
600    la ra, interrupt17
601    j _start_trap_direct
602_start_trap18:
603    addi sp, sp, -40*4
604    sw ra, 0(sp)
605    la ra, interrupt18
606    j _start_trap_direct
607_start_trap19:
608    addi sp, sp, -40*4
609    sw ra, 0(sp)
610    la ra, interrupt19
611    j _start_trap_direct
612_start_trap20:
613    addi sp, sp, -40*4
614    sw ra, 0(sp)
615    la ra, interrupt20
616    j _start_trap_direct
617_start_trap21:
618    addi sp, sp, -40*4
619    sw ra, 0(sp)
620    la ra, interrupt21
621    j _start_trap_direct
622_start_trap22:
623    addi sp, sp, -40*4
624    sw ra, 0(sp)
625    la ra, interrupt22
626    j _start_trap_direct
627_start_trap23:
628    addi sp, sp, -40*4
629    sw ra, 0(sp)
630    la ra, interrupt23
631    j _start_trap_direct
632_start_trap24:
633    addi sp, sp, -40*4
634    sw ra, 0(sp)
635    la ra, interrupt24
636    j _start_trap_direct
637_start_trap25:
638    addi sp, sp, -40*4
639    sw ra, 0(sp)
640    la ra, interrupt25
641    j _start_trap_direct
642_start_trap26:
643    addi sp, sp, -40*4
644    sw ra, 0(sp)
645    la ra, interrupt26
646    j _start_trap_direct
647_start_trap27:
648    addi sp, sp, -40*4
649    sw ra, 0(sp)
650    la ra, interrupt27
651    j _start_trap_direct
652_start_trap28:
653    addi sp, sp, -40*4
654    sw ra, 0(sp)
655    la ra, interrupt28
656    j _start_trap_direct
657_start_trap29:
658    addi sp, sp, -40*4
659    sw ra, 0(sp)
660    la ra, interrupt29
661    j _start_trap_direct
662_start_trap30:
663    addi sp, sp, -40*4
664    sw ra, 0(sp)
665    la ra, interrupt30
666    j _start_trap_direct
667_start_trap31:
668    addi sp, sp, -40*4
669    sw ra, 0(sp)
670    la ra, interrupt31
671    j _start_trap_direct
672la ra, _start_trap_rust_hal /* this runs on exception, use regular fault handler */
673_start_trap_direct:
674"#,
675r#"
676    sw t0, 1*4(sp)
677    sw t1, 2*4(sp)
678    sw t2, 3*4(sp)
679    sw t3, 4*4(sp)
680    sw t4, 5*4(sp)
681    sw t5, 6*4(sp)
682    sw t6, 7*4(sp)
683    sw a0, 8*4(sp)
684    sw a1, 9*4(sp)
685    sw a2, 10*4(sp)
686    sw a3, 11*4(sp)
687    sw a4, 12*4(sp)
688    sw a5, 13*4(sp)
689    sw a6, 14*4(sp)
690    sw a7, 15*4(sp)
691    sw s0, 16*4(sp)
692    sw s1, 17*4(sp)
693    sw s2, 18*4(sp)
694    sw s3, 19*4(sp)
695    sw s4, 20*4(sp)
696    sw s5, 21*4(sp)
697    sw s6, 22*4(sp)
698    sw s7, 23*4(sp)
699    sw s8, 24*4(sp)
700    sw s9, 25*4(sp)
701    sw s10, 26*4(sp)
702    sw s11, 27*4(sp)
703    sw gp, 28*4(sp)
704    sw tp, 29*4(sp)
705    csrrs t1, mepc, x0
706    sw t1, 31*4(sp)
707    csrrs t1, mstatus, x0
708    sw t1, 32*4(sp)
709    csrrs t1, mcause, x0
710    sw t1, 33*4(sp)
711    csrrs t1, mtval, x0
712    sw t1, 34*4(sp)
713
714    addi s0, sp, 40*4
715    sw s0, 30*4(sp)
716
717    add a0, sp, zero
718    "#,
719    // store current priority, set threshold, enable interrupts
720    r#"
721    addi sp, sp, -16 #build stack
722    sw ra, 0(sp)
723    jal ra, _handle_priority
724    lw ra, 0(sp)
725    sw a0, 0(sp) #reuse old stack, a0 is return of _handle_priority
726    addi a0, sp, 16 #the proper stack pointer is an argument to the HAL handler
727    "#,
728    // jump to handler loaded in direct handler
729    r#"
730    jalr ra, ra #jump to label loaded in _start_trapx
731    "#,
732    // restore threshold
733    r#"
734    lw a0, 0(sp) #load stored priority
735    jal ra, _restore_priority
736    addi sp, sp, 16 #pop
737    "#,
738    r#"
739    lw t1, 31*4(sp)
740    csrrw x0, mepc, t1
741
742    lw t1, 32*4(sp)
743    csrrw x0, mstatus, t1
744
745    lw ra, 0*4(sp)
746    lw t0, 1*4(sp)
747    lw t1, 2*4(sp)
748    lw t2, 3*4(sp)
749    lw t3, 4*4(sp)
750    lw t4, 5*4(sp)
751    lw t5, 6*4(sp)
752    lw t6, 7*4(sp)
753    lw a0, 8*4(sp)
754    lw a1, 9*4(sp)
755    lw a2, 10*4(sp)
756    lw a3, 11*4(sp)
757    lw a4, 12*4(sp)
758    lw a5, 13*4(sp)
759    lw a6, 14*4(sp)
760    lw a7, 15*4(sp)
761    lw s0, 16*4(sp)
762    lw s1, 17*4(sp)
763    lw s2, 18*4(sp)
764    lw s3, 19*4(sp)
765    lw s4, 20*4(sp)
766    lw s5, 21*4(sp)
767    lw s6, 22*4(sp)
768    lw s7, 23*4(sp)
769    lw s8, 24*4(sp)
770    lw s9, 25*4(sp)
771    lw s10, 26*4(sp)
772    lw s11, 27*4(sp)
773    lw gp, 28*4(sp)
774    lw tp, 29*4(sp)
775    lw sp, 30*4(sp)
776
777    # SP was restored from the original SP
778    mret
779
780/* Make sure there is an abort when linking */
781.section .text.abort
782.globl abort
783abort:
784    j abort
785
786/*
787    Interrupt vector table (_vector_table)
788*/
789
790.section .trap, "ax"
791.weak _vector_table
792.type _vector_table, @function
793
794.option push
795.balign 0x100
796.option norelax
797.option norvc
798
799_vector_table:
800    j _start_trap
801    j _start_trap1
802    j _start_trap2
803    j _start_trap3
804    j _start_trap4
805    j _start_trap5
806    j _start_trap6
807    j _start_trap7
808    j _start_trap8
809    j _start_trap9
810    j _start_trap10
811    j _start_trap11
812    j _start_trap12
813    j _start_trap13
814    j _start_trap14
815    j _start_trap15
816    j _start_trap16
817    j _start_trap17
818    j _start_trap18
819    j _start_trap19
820    j _start_trap20
821    j _start_trap21
822    j _start_trap22
823    j _start_trap23
824    j _start_trap24
825    j _start_trap25
826    j _start_trap26
827    j _start_trap27
828    j _start_trap28
829    j _start_trap29
830    j _start_trap30
831    j _start_trap31
832.option pop
833"#,
834r#"
835#this is required for the linking step, these symbols for in-use interrupts should always be overwritten by the user.
836.section .trap, "ax"
837// See https://github.com/esp-rs/esp-hal/issues/1326 and https://reviews.llvm.org/D98762
838// and yes, this all has to go on one line... *sigh*.
839.lto_discard interrupt1, interrupt2, interrupt3, interrupt4, interrupt5, interrupt6, interrupt7, interrupt8, interrupt9, interrupt10, interrupt11, interrupt12, interrupt13, interrupt14, interrupt15, interrupt16, interrupt17, interrupt18, interrupt19, interrupt20, interrupt21, interrupt22, interrupt23, interrupt24, interrupt25, interrupt26, interrupt27, interrupt28, interrupt29, interrupt30, interrupt31
840.weak interrupt1
841.weak interrupt2
842.weak interrupt3
843.weak interrupt4
844.weak interrupt5
845.weak interrupt6
846.weak interrupt7
847.weak interrupt8
848.weak interrupt9
849.weak interrupt10
850.weak interrupt11
851.weak interrupt12
852.weak interrupt13
853.weak interrupt14
854.weak interrupt15
855.weak interrupt16
856.weak interrupt17
857.weak interrupt18
858.weak interrupt19
859.weak interrupt20
860.weak interrupt21
861.weak interrupt22
862.weak interrupt23
863.weak interrupt24
864.weak interrupt25
865.weak interrupt26
866.weak interrupt27
867.weak interrupt28
868.weak interrupt29
869.weak interrupt30
870.weak interrupt31
871"#,
872}