xtensa_lx_rt/exception/
asm.rs

1use core::arch::global_asm;
2
3use crate::cfg_global_asm;
4
5// We could cfg symbols away and reduce frame size depending on features enabled
6// i.e the frame size is a fixed size based on all the features right now
7// we know at compile time if a target has loops for example, if it doesn't
8// we could cut that memory usage.
9// However in order to conveniently use `addmi` we need 256-byte alignment
10// anyway so wasting a bit more stack space seems to be the better option.
11//
12// The only exception is XT_STK_F64R_LO_CPENABLE which combines two register
13// values depending on `float-save-restore` feature. This is done so that their
14// position stays the same in `Context` without creating a large hole in the
15// struct.
16//
17// Additionally there is a chunk of memory reserved for spilled registers.
18//
19// With the exception of XT_STK_TMP, the fields must be aligned with the
20// `Context` struct in context.rs
21global_asm!(
22    "
23    .set XT_STK_PC,              0
24    .set XT_STK_PS,              4
25    .set XT_STK_A0,              8
26    .equ XT_STK_A1,             12
27    .set XT_STK_A2,             16
28    .set XT_STK_A3,             20
29    .set XT_STK_A4,             24
30    .set XT_STK_A5,             28
31    .set XT_STK_A6,             32
32    .set XT_STK_A7,             36
33    .set XT_STK_A8,             40
34    .set XT_STK_A9,             44
35    .set XT_STK_A10,            48
36    .set XT_STK_A11,            52
37    .set XT_STK_A12,            56
38    .set XT_STK_A13,            60
39    .set XT_STK_A14,            64
40    .set XT_STK_A15,            68
41    .set XT_STK_SAR,            72
42    .set XT_STK_EXCCAUSE,       76
43    .set XT_STK_EXCVADDR,       80
44    .set XT_STK_LBEG,           84 // Registers for Loop Option
45    .set XT_STK_LEND,           88
46    .set XT_STK_LCOUNT,         92
47    .set XT_STK_THREADPTR,      96 // freely usable 32-bit register intended for TLS
48    .set XT_STK_SCOMPARE1,     100 // Register for s32ci instruction
49    .set XT_STK_BR,            104 // Register for Boolean Option
50    .set XT_STK_ACCLO,         108 // Registers for MAC16 option
51    .set XT_STK_ACCHI,         112
52    .set XT_STK_M0,            116
53    .set XT_STK_M1,            120
54    .set XT_STK_M2,            124
55    .set XT_STK_M3,            128
56    // if `float-save-restore` is enabled: Registers for double support option.
57    // Otherwise, the saved value of CPENABLE
58    .set XT_STK_F64R_LO_CPENABLE, 132
59    .set XT_STK_F64R_HI,       136
60    .set XT_STK_F64S,          140
61    .set XT_STK_FCR,           144 // Registers for floating point coprocessor
62    .set XT_STK_FSR,           148
63    .set XT_STK_F0,            152
64    .set XT_STK_F1,            156
65    .set XT_STK_F2,            160
66    .set XT_STK_F3,            164
67    .set XT_STK_F4,            168
68    .set XT_STK_F5,            172
69    .set XT_STK_F6,            176
70    .set XT_STK_F7,            180
71    .set XT_STK_F8,            184
72    .set XT_STK_F9,            188
73    .set XT_STK_F10,           192
74    .set XT_STK_F11,           196
75    .set XT_STK_F12,           200
76    .set XT_STK_F13,           204
77    .set XT_STK_F14,           208
78    .set XT_STK_F15,           212
79    .set XT_STK_TMP,           216
80
81    .set XT_STK_FRMSZ,         256      // needs to be multiple of 16 and enough additional free space
82                                        // for the registers spilled to the stack (max 8 registers / 0x20 bytes)
83                                        // multiple of 256 allows use of addmi instruction
84
85
86
87    .set PS_INTLEVEL_EXCM, 3	        // interrupt handlers above this level shouldn't be written in high level languages
88    .set PS_INTLEVEL_MASK, 0x0000000f
89    .set PS_EXCM,          0x00000010
90    .set PS_UM,            0x00000020
91    .set PS_WOE,           0x00040000
92
93    // Spills all active windowed registers (i.e. registers not visible as
94    // A0-A15) to their ABI-defined spill regions on the stack.
95    // It will spill registers to their reserved locations in previous frames.
96    //
97    // Unlike the Xtensa HAL implementation, this code requires that the
98    // EXCM and WOE bit be enabled in PS, and relies on repeated hardware
99    // exception handling to do the register spills.  The trick is to do a
100    // noop write to the high registers, which the hardware will trap
101    // (into an overflow exception) in the case where those registers are
102    // already used by an existing call frame.  Then it rotates the window
103    // and repeats until all but the A0-A3 registers of the original frame
104    // are guaranteed to be spilled, eventually rotating back around into
105    // the original frame.  Advantages:
106    //
107    // - Vastly smaller code size
108    //
109    // - More easily maintained if changes are needed to window over/underflow
110    //   exception handling.
111    //
112    // - Requires no scratch registers to do its work, so can be used safely in any
113    //   context.
114    //
115    // - If the WOE bit is not enabled (for example, in code written for
116    //   the CALL0 ABI), this becomes a silent noop and operates compatbily.
117    //
118    // - Hilariously it's ACTUALLY FASTER than the HAL routine.  And not
119    //   just a little bit, it's MUCH faster.  With a mostly full register
120    //   file on an LX6 core (ESP-32) I'm measuring 145 cycles to spill
121    //   registers with this vs. 279 (!) to do it with
122    //   xthal_spill_windows().
123
124    .macro SPILL_REGISTERS
125    and a12, a12, a12
126    rotw 3
127    and a12, a12, a12
128    rotw 3
129    and a12, a12, a12
130    rotw 3
131    and a12, a12, a12
132    rotw 3
133    and a12, a12, a12
134    rotw 4
135    .endm
136
137    .macro SAVE_CONTEXT level:req
138    mov     a0, a1                     // save a1/sp
139    addmi   sp, sp, -XT_STK_FRMSZ      // only allow multiple of 256
140
141    s32i    a0, sp, +XT_STK_A1         // save interruptee's A1/SP
142    s32e    a0, sp, -12                // for debug backtrace
143
144    .ifc \\level,1
145    rsr     a0, PS
146    s32i    a0, sp, +XT_STK_PS         // save interruptee's PS
147
148    rsr     a0, EXCCAUSE
149    s32i    a0, sp, +XT_STK_EXCCAUSE
150    rsr     a0, EXCVADDR
151    s32i    a0, sp, +XT_STK_EXCVADDR
152    .else
153    rsr     a0, EPS\\level
154    s32i    a0, sp, +XT_STK_PS         // save interruptee's PS
155    .endif
156
157    rsr     a0, EPC\\level
158    s32i    a0, sp, +XT_STK_PC         // save interruptee's PC
159    s32e    a0, sp, -16                // for debug backtrace
160
161    rsr     a0, EXCSAVE\\level
162    s32i    a0, sp, +XT_STK_A0         // save interruptee's A0
163
164    call0   save_context
165
166    .endm
167
168    .macro RESTORE_CONTEXT level:req
169
170    // Restore context and return
171    call0   restore_context
172
173    .ifc \\level,1
174    l32i    a0, sp, +XT_STK_PS        // retrieve interruptee's PS
175    wsr     a0, PS
176    l32i    a0, sp, +XT_STK_PC        // retrieve interruptee's PC
177    wsr     a0, EPC\\level
178    .else
179    l32i    a0, sp, +XT_STK_PS        // retrieve interruptee's PS
180    wsr     a0, EPS\\level
181    l32i    a0, sp, +XT_STK_PC        // retrieve interruptee's PC
182    wsr     a0, EPC\\level
183    .endif
184
185    l32i    a0, sp, +XT_STK_A0        // retrieve interruptee's A0
186    l32i    sp, sp, +XT_STK_A1        // remove exception frame
187    rsync                             // ensure PS and EPC written
188
189    .endm
190
191    .macro HANDLE_INTERRUPT_LEVEL level
192    SAVE_CONTEXT \\level
193
194    movi    a0, (\\level | PS_WOE)
195    wsr     a0, PS
196    rsync
197
198    mov     a6, sp                         // put address of save frame in a6=a2 in callee
199    call4   __level_\\level\\()_interrupt    // call handler <= actual call!
200
201    RESTORE_CONTEXT \\level
202    rfi \\level
203
204    .endm
205    "
206);
207
208cfg_global_asm!(
209    "
210    // Save processor state to stack.
211    //
212    // *Must only be called with call0.*
213    // *For spill all window registers to work WOE must be enabled on entry
214    //
215    // Saves all registers except PC, PS, A0, A1
216    //
217    // Inputs:
218    //     A0 is the return address
219    //     A1 is the stack pointers
220    //     Exceptions are disabled (PS.EXCM = 1)
221    //
222    // Output:
223    //     A0 is the return address
224    //     A1 is the stack pointer
225    //     A3, A9 are used as scratch registers
226    //     EPC1 is changed
227    .section .rwtext,\"ax\",@progbits
228    .global save_context
229    .p2align 2
230    .type save_context,@function
231save_context:
232.Lsave_context_start:
233    s32i    a2,  sp, +XT_STK_A2
234    s32i    a3,  sp, +XT_STK_A3
235    s32i    a4,  sp, +XT_STK_A4
236    s32i    a5,  sp, +XT_STK_A5
237    s32i    a6,  sp, +XT_STK_A6
238    s32i    a7,  sp, +XT_STK_A7
239    s32i    a8,  sp, +XT_STK_A8
240    s32i    a9,  sp, +XT_STK_A9
241    s32i    a10, sp, +XT_STK_A10
242    s32i    a11, sp, +XT_STK_A11
243    s32i    a12, sp, +XT_STK_A12
244    s32i    a13, sp, +XT_STK_A13
245    s32i    a14, sp, +XT_STK_A14
246    s32i    a15, sp, +XT_STK_A15
247
248    rsr     a3,  SAR
249    s32i    a3,  sp, +XT_STK_SAR
250    ",
251    #[cfg(all(XCHAL_HAVE_CP, not(feature = "float-save-restore")))]
252    "
253    /* Disable coprocessor, any use of floats in ISRs will cause an exception unless float-save-restore feature is enabled */
254    rsr     a3, CPENABLE
255    s32i    a3, sp, +XT_STK_F64R_LO_CPENABLE
256    movi    a3,  0
257    wsr     a3,  CPENABLE
258    rsync
259    ",
260    #[cfg(XCHAL_HAVE_LOOPS)]
261    "
262    // Loop Option
263    rsr     a3,  LBEG
264    s32i    a3,  sp, +XT_STK_LBEG
265    rsr     a3,  LEND
266    s32i    a3,  sp, +XT_STK_LEND
267    rsr     a3,  LCOUNT
268    s32i    a3,  sp, +XT_STK_LCOUNT
269    ",
270    #[cfg(XCHAL_HAVE_THREADPTR)]
271    "
272    // Thread Pointer Option
273    rur     a3, threadptr
274    s32i    a3, sp, +XT_STK_THREADPTR
275    ",
276    #[cfg(XCHAL_HAVE_S32C1I)]
277    "
278    // Conditional Store Option
279    rsr     a3, scompare1
280    s32i    a3, sp, +XT_STK_SCOMPARE1
281    ",
282    #[cfg(XCHAL_HAVE_BOOLEANS)]
283    "
284    // Boolean Option
285    rsr     a3, br
286    s32i    a3, sp, +XT_STK_BR
287    ",
288    #[cfg(XCHAL_HAVE_MAC16)]
289    "
290    // MAC16 Option
291    rsr     a3, acclo
292    s32i    a3, sp, +XT_STK_ACCLO
293    rsr     a3, acchi
294    s32i    a3, sp, +XT_STK_ACCHI
295    rsr     a3, m0
296    s32i    a3, sp, +XT_STK_M0
297    rsr     a3, m1
298    s32i    a3, sp, +XT_STK_M1
299    rsr     a3, m2
300    s32i    a3, sp, +XT_STK_M2
301    rsr     a3, m3
302    s32i    a3, sp, +XT_STK_M3
303    ",
304    #[cfg(all(feature = "float-save-restore", XCHAL_HAVE_DFP_ACCEL))]
305    "
306    // Double Precision Accelerator Option
307    rur     a3, f64r_lo
308    s32i    a3, sp, +XT_STK_F64R_LO_CPENABLE
309    rur     a3, f64r_hi
310    s32i    a3, sp, +XT_STK_F64R_HI
311    rur     a3, f64s
312    s32i    a3, sp, +XT_STK_F64S
313    ",
314    #[cfg(all(feature = "float-save-restore", XCHAL_HAVE_FP))]
315    "
316    // Coprocessor Option
317    rur     a3, fcr
318    s32i    a3, sp, +XT_STK_FCR
319    rur     a3, fsr
320    s32i    a3, sp, +XT_STK_FSR
321    ssi     f0, sp, +XT_STK_F0
322    ssi     f1, sp, +XT_STK_F1
323    ssi     f2, sp, +XT_STK_F2
324    ssi     f3, sp, +XT_STK_F3
325    ssi     f4, sp, +XT_STK_F4
326    ssi     f5, sp, +XT_STK_F5
327    ssi     f6, sp, +XT_STK_F6
328    ssi     f7, sp, +XT_STK_F7
329    ssi     f8, sp, +XT_STK_F8
330    ssi     f9, sp, +XT_STK_F9
331    ssi     f10, sp, +XT_STK_F10
332    ssi     f11, sp, +XT_STK_F11
333    ssi     f12, sp, +XT_STK_F12
334    ssi     f13, sp, +XT_STK_F13
335    ssi     f14, sp, +XT_STK_F14
336    ssi     f15, sp, +XT_STK_F15
337    ",
338    #[cfg(XCHAL_HAVE_WINDOWED)]
339    "
340    s32i    a0, sp, +XT_STK_TMP        // keep return address on the stack
341
342    // SPILL_REGISTERS macro requires window overflow exceptions to be enabled,
343    // i.e. PS.EXCM cleared and PS.WOE set.
344    // Since we are going to clear PS.EXCM, we also need to increase INTLEVEL
345    // at least to XCHAL_EXCM_LEVEL. This matches that value of effective INTLEVEL
346    // at entry (CINTLEVEL=max(PS.INTLEVEL, XCHAL_EXCM_LEVEL) when PS.EXCM is set.
347    // Since WindowOverflow exceptions will trigger inside SPILL_REGISTERS,
348    // need to save/restore EPC1 as well.
349    // Note: even though a4-a15 are saved into the exception frame, we should not
350    // clobber them until after SPILL_REGISTERS. This is because these registers
351    // may contain live windows belonging to previous frames in the call stack.
352    // These frames will be spilled by SPILL_REGISTERS, and if the register was
353    // used as a temporary by this code, the temporary value would get stored
354    // onto the stack, instead of the real value.
355    //
356
357    rsr     a2, PS                     // to be restored after SPILL_REGISTERS
358    movi    a0, PS_INTLEVEL_MASK
359    and     a3, a2, a0                 // get the current INTLEVEL
360    bgeui   a3, +PS_INTLEVEL_EXCM, 1f  // calculate max(INTLEVEL, XCHAL_EXCM_LEVEL) - 3 = XCHAL_EXCM_LEVEL
361    movi    a3, PS_INTLEVEL_EXCM
362    1:
363    movi    a0, PS_WOE       // clear EXCM, enable window overflow, set new INTLEVEL
364    or      a3, a3, a0
365    wsr     a3, ps
366    rsr     a0, EPC1
367
368    addmi   sp,  sp, +XT_STK_FRMSZ   // go back to spill register region
369    SPILL_REGISTERS
370    addmi   sp,  sp, -XT_STK_FRMSZ   // return the current stack pointer
371
372    wsr     a2, PS                   //  restore to the value at entry
373    rsync
374    wsr     a0, EPC1
375
376    l32i    a0,  sp, +XT_STK_TMP
377    ",
378    "
379    ret
380.Lsave_context_end:
381    .size .Lsave_context_start, .Lsave_context_end
382
383    .section .rwtext,\"ax\",@progbits
384    .global restore_context
385    .p2align 2
386    .type restore_context,@function
387restore_context:
388.Lrestore_context_start:
389    l32i    a3,  sp, +XT_STK_SAR
390    wsr     a3,  SAR
391    ",
392    #[cfg(XCHAL_HAVE_LOOPS)]
393    "
394    // Loop Option
395    l32i    a3,  sp, +XT_STK_LBEG
396    wsr     a3,  LBEG
397    l32i    a3,  sp, +XT_STK_LEND
398    wsr     a3,  LEND
399    l32i    a3,  sp, +XT_STK_LCOUNT
400    wsr     a3,  LCOUNT
401    ",
402    #[cfg(XCHAL_HAVE_THREADPTR)]
403    "
404    // Thread Pointer Option
405    l32i    a3, sp, +XT_STK_THREADPTR
406    wur     a3, threadptr
407    ",
408    #[cfg(XCHAL_HAVE_S32C1I)]
409    "
410    // Conditional Store Option
411    l32i    a3, sp, +XT_STK_SCOMPARE1
412    wsr     a3, scompare1
413    ",
414    #[cfg(XCHAL_HAVE_BOOLEANS)]
415    "
416    // Boolean Option
417    l32i    a3, sp, +XT_STK_BR
418    wsr     a3, br
419    ",
420    #[cfg(XCHAL_HAVE_MAC16)]
421    "
422    // MAC16 Option
423    l32i    a3, sp, +XT_STK_ACCLO
424    wsr     a3, acclo
425    l32i    a3, sp, +XT_STK_ACCHI
426    wsr     a3, acchi
427    l32i    a3, sp, +XT_STK_M0
428    wsr     a3, m0
429    l32i    a3, sp, +XT_STK_M1
430    wsr     a3, m1
431    l32i    a3, sp, +XT_STK_M2
432    wsr     a3, m2
433    l32i    a3, sp, +XT_STK_M3
434    wsr     a3, m3
435    ",
436    #[cfg(all(feature = "float-save-restore", XCHAL_HAVE_DFP_ACCEL))]
437    "
438    // Double Precision Accelerator Option
439    l32i    a3, sp, +XT_STK_F64R_LO_CPENABLE
440    wur     a3, f64r_lo
441    l32i    a3, sp, +XT_STK_F64R_HI
442    wur     a3, f64r_hi
443    l32i    a3, sp, +XT_STK_F64S
444    wur     a3, f64s
445    ",
446    #[cfg(all(feature = "float-save-restore", XCHAL_HAVE_FP))]
447    "
448    // Coprocessor Option
449    l32i    a3, sp, +XT_STK_FCR
450    wur     a3, fcr
451    l32i    a3, sp, +XT_STK_FSR
452    wur     a3, fsr
453    lsi     f0, sp, +XT_STK_F0
454    lsi     f1, sp, +XT_STK_F1
455    lsi     f2, sp, +XT_STK_F2
456    lsi     f3, sp, +XT_STK_F3
457    lsi     f4, sp, +XT_STK_F4
458    lsi     f5, sp, +XT_STK_F5
459    lsi     f6, sp, +XT_STK_F6
460    lsi     f7, sp, +XT_STK_F7
461    lsi     f8, sp, +XT_STK_F8
462    lsi     f9, sp, +XT_STK_F9
463    lsi     f10, sp, +XT_STK_F10
464    lsi     f11, sp, +XT_STK_F11
465    lsi     f12, sp, +XT_STK_F12
466    lsi     f13, sp, +XT_STK_F13
467    lsi     f14, sp, +XT_STK_F14
468    lsi     f15, sp, +XT_STK_F15
469    ",
470    #[cfg(all(XCHAL_HAVE_CP, not(feature = "float-save-restore")))]
471    "
472    /* Restore coprocessor state after ISR */
473    l32i    a3, sp, +XT_STK_F64R_LO_CPENABLE
474    wsr     a3,  CPENABLE
475    rsync
476    ",
477    "
478    // general registers
479    l32i    a2,  sp, +XT_STK_A2
480    l32i    a3,  sp, +XT_STK_A3
481    l32i    a4,  sp, +XT_STK_A4
482    l32i    a5,  sp, +XT_STK_A5
483    l32i    a6,  sp, +XT_STK_A6
484    l32i    a7,  sp, +XT_STK_A7
485    l32i    a8,  sp, +XT_STK_A8
486    l32i    a9,  sp, +XT_STK_A9
487    l32i    a10, sp, +XT_STK_A10
488    l32i    a11, sp, +XT_STK_A11
489    l32i    a12, sp, +XT_STK_A12
490    l32i    a13, sp, +XT_STK_A13
491    l32i    a14, sp, +XT_STK_A14
492    l32i    a15, sp, +XT_STK_A15
493    ret
494.Lrestore_context_end:
495    .size .Lrestore_context_start, .Lrestore_context_end
496    ",
497);
498
499global_asm!(
500    "
501    // Handle Other Exceptions or Level 1 interrupt by storing full context and
502    // then calling regular function
503    //
504    // # Input:
505    //    * A0 stored in EXCSAVE1
506
507    .section .rwtext,\"ax\",@progbits
508    .global __default_naked_exception
509    .p2align 2
510    .type __default_naked_exception,@function
511__default_naked_exception:
512.Ldefault_naked_exception_start:
513    SAVE_CONTEXT 1
514
515    l32i    a6, sp, +XT_STK_EXCCAUSE  // put cause in a6 = a2 in callee
516
517    bnei    a6, 4, .HandleException   // Handle exception elsewhere
518
519    movi    a0, (1 | PS_WOE)          // set PS.INTLEVEL accordingly
520    wsr     a0, PS
521    rsync
522    mov     a6, sp                    // put address of save frame in a6=a2 in callee
523
524    call4   __level_1_interrupt       // call handler <= actual call!
525
526.RestoreContext:
527    RESTORE_CONTEXT 1
528
529    rfe                               // PS.EXCM is cleared
530
531.HandleException:
532    mov     a7, sp                    // put address of save frame in a7=a3 in callee
533
534    movi    a0, (PS_INTLEVEL_EXCM | PS_WOE)
535    wsr     a0, PS
536    rsync
537
538    call4   __exception               // call handler <= actual call!
539    j       .RestoreContext
540
541.Ldefault_naked_exception_end:
542    .size .Ldefault_naked_exception_start, .Ldefault_naked_exception_end
543
544    // Handle Double Exceptions by storing full context and then calling regular
545    // function Double exceptions are not a normal occurrence. They indicate a bug
546    // of some kind.
547    //
548    // # Input:
549    //    * A0 stored in EXCSAVE1
550    .section .rwtext,\"ax\",@progbits
551    .global __default_naked_double_exception
552    .p2align 2
553    .type __default_naked_double_exception,@function
554__default_naked_double_exception:
555.Ldefault_double_naked_exception_start:
556    mov     a0, a1                     // save a1/sp
557    addmi   sp, sp, -XT_STK_FRMSZ      // only allow multiple of 256
558
559    s32i    a0, sp, +XT_STK_A1         // save interruptee's A1/SP
560    s32e    a0, sp, -12                // for debug backtrace
561
562    rsr     a0, PS
563    s32i    a0, sp, +XT_STK_PS         // save interruptee's PS
564
565    rsr     a0, EXCCAUSE
566    s32i    a0, sp, +XT_STK_EXCCAUSE
567    rsr     a0, EXCVADDR
568    s32i    a0, sp, +XT_STK_EXCVADDR
569
570    rsr     a0, DEPC
571    s32i    a0, sp, +XT_STK_PC         // save interruptee's PC
572    s32e    a0, sp, -16                // for debug backtrace
573
574    rsr     a0, EXCSAVE7               // ok to reuse EXCSAVE7 for double exception as long as
575                                        // double exception is not in first couple of instructions
576                                        // of level 7 handler
577    s32i    a0, sp, +XT_STK_A0         // save interruptee's A0
578
579    call0   save_context
580
581    l32i    a6, sp, +XT_STK_EXCCAUSE  // put cause in a6 = a2 in callee
582    mov     a7, sp                    // put address of save frame in a7=a3 in callee
583    call4   __exception               // call handler <= actual call!
584
585    // Restore context and return
586    call0   restore_context
587
588    l32i    a0, sp, +XT_STK_PS        // retrieve interruptee's PS
589    wsr     a0, PS
590    l32i    a0, sp, +XT_STK_PC        // retrieve interruptee's PC
591    wsr     a0, EPC1
592
593    l32i    a0, sp, +XT_STK_A0        // retrieve interruptee's A0
594    l32i    sp, sp, +XT_STK_A1        // remove exception frame
595    rsync                             // ensure PS and EPC written
596
597    rfde
598.Ldefault_double_naked_exception_end:
599    .size .Ldefault_double_naked_exception_start, .Ldefault_double_naked_exception_end
600
601    // Handle Level 2 Interrupt by storing full context and then calling regular
602    // function
603    //
604    // # Input:
605    //    * A0 stored in EXCSAVE2
606    .section .rwtext,\"ax\",@progbits
607    .global __default_naked_level_2_interrupt
608    .p2align 2
609    .type __default_naked_level_2_interrupt,@function
610__default_naked_level_2_interrupt:
611.Ldefault_naked_level_2_interrupt_start:
612    HANDLE_INTERRUPT_LEVEL 2
613.Ldefault_naked_level_2_interrupt_end:
614    .size .Ldefault_naked_level_2_interrupt_start, .Ldefault_naked_level_2_interrupt_end
615
616    // Handle Level 3 Interrupt by storing full context and then calling regular
617    // function
618    //
619    // # Input:
620    //    * A0 stored in EXCSAVE3
621    .section .rwtext,\"ax\",@progbits
622    .global __default_naked_level_3_interrupt
623    .p2align 2
624    .type __default_naked_level_3_interrupt,@function
625__default_naked_level_3_interrupt:
626.Ldefault_naked_level_3_interrupt_start:
627    HANDLE_INTERRUPT_LEVEL 3
628.Ldefault_naked_level_3_interrupt_end:
629    .size .Ldefault_naked_level_3_interrupt_start, .Ldefault_naked_level_3_interrupt_end
630
631    // Handle Level 4 Interrupt by storing full context and then calling regular
632    // function
633    //
634    // # Input:
635    //    * A0 stored in EXCSAVE4
636    .section .rwtext,\"ax\",@progbits
637    .global __default_naked_level_4_interrupt
638    .p2align 2
639    .type __default_naked_level_4_interrupt,@function
640__default_naked_level_4_interrupt:
641.Ldefault_naked_level_4_interrupt_start:
642    HANDLE_INTERRUPT_LEVEL 4
643.Ldefault_naked_level_4_interrupt_end:
644    .size .Ldefault_naked_level_4_interrupt_start, .Ldefault_naked_level_4_interrupt_end
645
646    // Handle Level 5 Interrupt by storing full context and then calling regular
647    // function
648    //
649    // # Input:
650    //    * A0 stored in EXCSAVE5
651    .section .rwtext,\"ax\",@progbits
652    .global __default_naked_level_5_interrupt
653    .p2align 2
654    .type __default_naked_level_5_interrupt,@function
655__default_naked_level_5_interrupt:
656.Ldefault_naked_level_5_interrupt_start:
657    HANDLE_INTERRUPT_LEVEL 5
658.Ldefault_naked_level_5_interrupt_end:
659    .size .Ldefault_naked_level_5_interrupt_start, .Ldefault_naked_level_5_interrupt_end
660
661    // Handle Level 6 (=Debug) Interrupt by storing full context and then calling
662    // regular function
663    //
664    // # Input:
665    //    * A0 stored in EXCSAVE6
666    .section .rwtext,\"ax\",@progbits
667    .global __default_naked_level_6_interrupt
668    .p2align 2
669    .type __default_naked_level_6_interrupt,@function
670__default_naked_level_6_interrupt:
671.Ldefault_naked_level_6_interrupt_start:
672    HANDLE_INTERRUPT_LEVEL 6
673.Ldefault_naked_level_6_interrupt_end:
674    .size .Ldefault_naked_level_6_interrupt_start, .Ldefault_naked_level_6_interrupt_end
675
676    // Handle Level 7 (=NMI) Interrupt by storing full context and then calling
677    // regular function
678    //
679    // # Input:
680    //    * A0 stored in EXCSAVE7
681    .section .rwtext,\"ax\",@progbits
682    .global __default_naked_level_7_interrupt
683    .p2align 2
684    .type __default_naked_level_7_interrupt,@function
685__default_naked_level_7_interrupt:
686.Ldefault_naked_level_7_interrupt_start:
687    HANDLE_INTERRUPT_LEVEL 7
688.Ldefault_naked_level_7_interrupt_end:
689    .size .Ldefault_naked_level_7_interrupt_start, .Ldefault_naked_level_7_interrupt_end
690"
691);
692
693// Raw vector handlers
694//
695// The interrupt handlers all use special return instructions.
696// rust still generates a ret.w instruction, which will never be reached.
697// generation of the ret.w can be prevented by using
698// core::intrinsics::unreachable, but then a break 15,1 will be generated (which
699// takes 3 bytes instead of 2) or a 'loop {}', but then a jump to own address
700// will be generated which is also 3 bytes. No way found yet to prevent this
701// generation altogether.
702global_asm!(
703    "
704    .section .WindowOverflow8.text,\"ax\",@progbits
705    .global _WindowOverflow8
706    .p2align 2
707    .type _WindowOverflow8,@function
708_WindowOverflow8:
709        s32e    a0, a9, -16
710        l32e    a0, a1, -12
711
712        s32e    a1, a9, -12
713        s32e    a2, a9,  -8
714        s32e    a3, a9,  -4
715        s32e    a4, a0, -32
716        s32e    a5, a0, -28
717        s32e    a6, a0, -24
718        s32e    a7, a0, -20
719        rfwo
720
721    .section .WindowUnderflow8.text,\"ax\",@progbits
722    .global _WindowUnderflow8
723    .p2align 2
724    .type _WindowUnderflow8,@function
725_WindowUnderflow8:
726        l32e    a0, a9, -16
727        l32e    a1, a9, -12
728        l32e    a2, a9,  -8
729        l32e    a7, a1, -12
730
731        l32e    a3, a9,  -4
732        l32e    a4, a7, -32
733        l32e    a5, a7, -28
734        l32e    a6, a7, -24
735        l32e    a7, a7, -20
736        rfwu
737
738    .section .WindowOverflow12.text,\"ax\",@progbits
739    .global _WindowOverflow12
740    .p2align 2
741    .type _WindowOverflow12,@function
742_WindowOverflow12:
743        s32e    a0,  a13, -16
744        l32e    a0,  a1,  -12
745
746        s32e    a1,  a13, -12
747        s32e    a2,  a13,  -8
748        s32e    a3,  a13,  -4
749        s32e    a4,  a0,  -48
750        s32e    a5,  a0,  -44
751        s32e    a6,  a0,  -40
752        s32e    a7,  a0,  -36
753        s32e    a8,  a0,  -32
754        s32e    a9,  a0,  -28
755        s32e    a10, a0,  -24
756        s32e    a11, a0,  -20
757        rfwo
758
759    .section .WindowUnderflow12.text,\"ax\",@progbits
760    .global _WindowUnderflow12
761    .p2align 2
762    .type _WindowUnderflow12,@function
763_WindowUnderflow12:
764        l32e    a0,  a13, -16
765        l32e    a1,  a13, -12
766        l32e    a2,  a13,  -8
767        l32e    a11, a1,  -12
768
769        l32e    a3,  a13,  -4
770        l32e    a4,  a11, -48
771        l32e    a5,  a11, -44
772        l32e    a6,  a11, -40
773        l32e    a7,  a11, -36
774        l32e    a8,  a11, -32
775        l32e    a9,  a11, -28
776        l32e    a10, a11, -24
777        l32e    a11, a11, -20
778        rfwu
779
780    .section .WindowOverflow4.text,\"ax\",@progbits
781    .global _WindowOverflow4
782    .p2align 2
783    .type _WindowOverflow4,@function
784_WindowOverflow4:
785        s32e    a0, a5, -16
786        s32e    a1, a5, -12
787        s32e    a2, a5,  -8
788        s32e    a3, a5,  -4
789        rfwo
790
791    .section .WindowUnderflow4.text,\"ax\",@progbits
792    .global _WindowUnderflow4
793    .p2align 2
794    .type _WindowUnderflow4,@function
795_WindowUnderflow4:
796        l32e    a0, a5, -16
797        l32e    a1, a5, -12
798        l32e    a2, a5,  -8
799        l32e    a3, a5,  -4
800        rfwu
801
802        // inline the _AllocAException saves on the ret.w for WindowUnderflow4
803        // this makes that it just fits, which is needed for the bbci instructions
804
805        .align 4
806        _AllocAException:
807        rsr     a0, WINDOWBASE  // grab WINDOWBASE before rotw changes it
808        rotw    -1              // WINDOWBASE goes to a4, new a0-a3 are scratch
809        rsr     a2, PS
810        extui   a3, a2, 8, 4    // XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS
811        xor     a3, a3, a4      // bits changed from old to current windowbase
812        rsr     a4, EXCSAVE1    // restore original a0 (now in a4)
813        slli    a3, a3, 8       // XCHAL_PS_OWB_SHIFT
814        xor     a2, a2, a3      // flip changed bits in old window base
815        wsr     a2, PS          // update PS.OWB to new window base
816        rsync
817
818        bbci    a4, 31, _WindowUnderflow4
819        rotw    -1              // original a0 goes to a8
820        bbci    a8, 30, _WindowUnderflow8
821        rotw    -1
822        j               _WindowUnderflow12
823
824    .section .KernelExceptionVector.text,\"ax\",@progbits
825    .global _KernelExceptionVector
826    .p2align 2
827    .type _KernelExceptionVector,@function
828_KernelExceptionVector:
829        wsr a0, EXCSAVE1 // preserve a0
830        rsr a0, EXCCAUSE // get exception cause
831
832        beqi a0, 5, .AllocAException
833
834        call0 __naked_kernel_exception
835
836    .section .UserExceptionVector.text,\"ax\",@progbits
837    .global _UserExceptionVector
838    .p2align 2
839    .type _UserExceptionVector,@function
840_UserExceptionVector:
841        wsr a0, EXCSAVE1 // preserve a0
842        rsr a0, EXCCAUSE // get exception cause
843
844        beqi a0, 5, .AllocAException
845
846        call0 __naked_user_exception
847
848.AllocAException:
849        call0  _AllocAException
850
851    .section .DoubleExceptionVector.text,\"ax\",@progbits
852    .global _DoubleExceptionVector
853    .p2align 2
854    .type _DoubleExceptionVector,@function
855_DoubleExceptionVector:
856        wsr a0, EXCSAVE1                // preserve a0 (EXCSAVE1 can be reused as long as there
857                                        // is no double exception in the first exception until
858                                        // EXCSAVE1 is stored to the stack.)
859        call0 __naked_double_exception  // used as long jump
860
861    .section .Level2InterruptVector.text,\"ax\",@progbits
862    .global _Level2InterruptVector
863    .p2align 2
864    .type _Level2InterruptVector,@function
865_Level2InterruptVector:
866        wsr a0, EXCSAVE2 // preserve a0
867        call0 __naked_level_2_interrupt     // used as long jump
868
869    .section .Level3InterruptVector.text,\"ax\",@progbits
870    .global _Level3InterruptVector
871    .p2align 2
872    .type _Level3InterruptVector,@function
873_Level3InterruptVector:
874        wsr a0, EXCSAVE3 // preserve a0
875        call0 __naked_level_3_interrupt     // used as long jump
876
877    .section .Level4InterruptVector.text,\"ax\",@progbits
878    .global _Level4InterruptVector
879    .p2align 2
880    .type _Level4InterruptVector,@function
881_Level4InterruptVector:
882        wsr a0, EXCSAVE4 // preserve a0
883        call0 __naked_level_4_interrupt     // used as long jump
884
885    .section .Level5InterruptVector.text,\"ax\",@progbits
886    .global _Level5InterruptVector
887    .p2align 2
888    .type _Level5InterruptVector,@function
889_Level5InterruptVector:
890        wsr a0, EXCSAVE5 // preserve a0
891        call0 __naked_level_5_interrupt     // used as long jump
892
893    .section .DebugExceptionVector.text,\"ax\",@progbits
894    .global _Level6InterruptVector
895    .p2align 2
896    .type _Level6InterruptVector,@function
897_Level6InterruptVector:
898        wsr a0, EXCSAVE6 // preserve a0
899        call0 __naked_level_6_interrupt     // used as long jump
900
901    .section .NMIExceptionVector.text,\"ax\",@progbits
902    .global _Level7InterruptVector
903    .p2align 2
904    .type _Level7InterruptVector,@function
905_Level7InterruptVector:
906        wsr a0, EXCSAVE7 // preserve a0
907        call0 __naked_level_7_interrupt     // used as long jump
908    "
909);