1use core::arch::global_asm;
2
3use crate::cfg_global_asm;
4
5global_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
693global_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);