1 /* 2 * FreeRTOS Kernel V11.1.0 3 * Copyright (C) 2015-2019 Cadence Design Systems, Inc. 4 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 * 6 * SPDX-License-Identifier: MIT 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 * this software and associated documentation files (the "Software"), to deal in 10 * the Software without restriction, including without limitation the rights to 11 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 * the Software, and to permit persons to whom the Software is furnished to do so, 13 * subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in all 16 * copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * https://www.FreeRTOS.org 26 * https://github.com/FreeRTOS 27 * 28 */ 29 30/* 31 XTENSA VECTORS AND LOW LEVEL HANDLERS FOR AN RTOS 32 33 Xtensa low level exception and interrupt vectors and handlers for an RTOS. 34 35 Interrupt handlers and user exception handlers support interaction with 36 the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT before and 37 after user's specific interrupt handlers. These macros are defined in 38 xtensa_<rtos>.h to call suitable functions in a specific RTOS. 39 40 Users can install application-specific interrupt handlers for low and 41 medium level interrupts, by calling xt_set_interrupt_handler(). These 42 handlers can be written in C, and must obey C calling convention. The 43 handler table is indexed by the interrupt number. Each handler may be 44 provided with an argument. 45 46 Note that the system timer interrupt is handled specially, and is 47 dispatched to the RTOS-specific handler. This timer cannot be hooked 48 by application code. 49 50 Optional hooks are also provided to install a handler per level at 51 run-time, made available by compiling this source file with 52 '-DXT_INTEXC_HOOKS' (useful for automated testing). 53 54!! This file is a template that usually needs to be modified to handle !! 55!! application specific interrupts. Search USER_EDIT for helpful comments !! 56!! on where to insert handlers and how to write them. !! 57 58 Users can also install application-specific exception handlers in the 59 same way, by calling xt_set_exception_handler(). One handler slot is 60 provided for each exception type. Note that some exceptions are handled 61 by the porting layer itself, and cannot be taken over by application 62 code in this manner. These are the alloca, syscall, and coprocessor 63 exceptions. 64 65 The exception handlers can be written in C, and must follow C calling 66 convention. Each handler is passed a pointer to an exception frame as 67 its single argument. The exception frame is created on the stack, and 68 holds the saved context of the thread that took the exception. If the 69 handler returns, the context will be restored and the instruction that 70 caused the exception will be retried. If the handler makes any changes 71 to the saved state in the exception frame, the changes will be applied 72 when restoring the context. 73 74 Because Xtensa is a configurable architecture, this port supports all user 75 generated configurations (except restrictions stated in the release notes). 76 This is accomplished by conditional compilation using macros and functions 77 defined in the Xtensa HAL (hardware adaptation layer) for your configuration. 78 Only the relevant parts of this file will be included in your RTOS build. 79 For example, this file provides interrupt vector templates for all types and 80 all priority levels, but only the ones in your configuration are built. 81 82 NOTES on the use of 'call0' for long jumps instead of 'j': 83 1. This file should be assembled with the -mlongcalls option to xt-xcc. 84 2. The -mlongcalls compiler option causes 'call0 dest' to be expanded to 85 a sequence 'l32r a0, dest' 'callx0 a0' which works regardless of the 86 distance from the call to the destination. The linker then relaxes 87 it back to 'call0 dest' if it determines that dest is within range. 88 This allows more flexibility in locating code without the performance 89 overhead of the 'l32r' literal data load in cases where the destination 90 is in range of 'call0'. There is an additional benefit in that 'call0' 91 has a longer range than 'j' due to the target being word-aligned, so 92 the 'l32r' sequence is less likely needed. 93 3. The use of 'call0' with -mlongcalls requires that register a0 not be 94 live at the time of the call, which is always the case for a function 95 call but needs to be ensured if 'call0' is used as a jump in lieu of 'j'. 96 4. This use of 'call0' is independent of the C function call ABI. 97 98 */ 99 100#include "xtensa_rtos.h" 101 102 103/* Enable stack backtrace across exception/interrupt - see below */ 104#define XT_DEBUG_BACKTRACE 1 105 106 107/* 108-------------------------------------------------------------------------------- 109 Defines used to access _xtos_interrupt_table. 110-------------------------------------------------------------------------------- 111*/ 112#define XIE_HANDLER 0 113#define XIE_ARG 4 114#define XIE_SIZE 8 115 116/* 117-------------------------------------------------------------------------------- 118 Macro extract_msb - return the input with only the highest bit set. 119 120 Input : "ain" - Input value, clobbered. 121 Output : "aout" - Output value, has only one bit set, MSB of "ain". 122 The two arguments must be different AR registers. 123-------------------------------------------------------------------------------- 124*/ 125 126 .macro extract_msb aout ain 1271: 128 addi \aout, \ain, -1 /* aout = ain - 1 */ 129 and \ain, \ain, \aout /* ain = ain & aout */ 130 bnez \ain, 1b /* repeat until ain == 0 */ 131 addi \aout, \aout, 1 /* return aout + 1 */ 132 .endm 133 134/* 135-------------------------------------------------------------------------------- 136 Macro dispatch_c_isr - dispatch interrupts to user ISRs. 137 This will dispatch to user handlers (if any) that are registered in the 138 XTOS dispatch table (_xtos_interrupt_table). These handlers would have 139 been registered by calling _xtos_set_interrupt_handler(). There is one 140 exception - the timer interrupt used by the OS will not be dispatched 141 to a user handler - this must be handled by the caller of this macro. 142 143 Level triggered and software interrupts are automatically deasserted by 144 this code. 145 146 ASSUMPTIONS: 147 -- PS.INTLEVEL is set to "level" at entry 148 -- PS.EXCM = 0, C calling enabled 149 150 NOTE: For CALL0 ABI, a12-a15 have not yet been saved. 151 152 NOTE: This macro will use registers a0 and a2-a6. The arguments are: 153 level -- interrupt level 154 mask -- interrupt bitmask for this level 155-------------------------------------------------------------------------------- 156*/ 157 158 .macro dispatch_c_isr level mask 159 160 /* Get mask of pending, enabled interrupts at this level into a2. */ 161 162.L_xt_user_int_&level&: 163 rsr a2, INTENABLE 164 rsr a3, INTERRUPT 165 movi a4, \mask 166 and a2, a2, a3 167 and a2, a2, a4 168 beqz a2, 9f /* nothing to do */ 169 170 /* This bit of code provides a nice debug backtrace in the debugger. 171 It does take a few more instructions, so undef XT_DEBUG_BACKTRACE 172 if you want to save the cycles. 173 */ 174 #if XT_DEBUG_BACKTRACE 175 #ifndef __XTENSA_CALL0_ABI__ 176 rsr a0, EPC_1 + \level - 1 /* return address */ 177 movi a4, 0xC0000000 /* constant with top 2 bits set (call size) */ 178 or a0, a0, a4 /* set top 2 bits */ 179 addx2 a0, a4, a0 /* clear top bit -- simulating call4 size */ 180 #endif 181 #endif 182 183 #ifdef XT_INTEXC_HOOKS 184 /* Call interrupt hook if present to (pre)handle interrupts. */ 185 movi a4, _xt_intexc_hooks 186 l32i a4, a4, \level << 2 187 beqz a4, 2f 188 #ifdef __XTENSA_CALL0_ABI__ 189 callx0 a4 190 beqz a2, 9f 191 #else 192 mov a6, a2 193 callx4 a4 194 beqz a6, 9f 195 mov a2, a6 196 #endif 1972: 198 #endif 199 200 /* Now look up in the dispatch table and call user ISR if any. */ 201 /* If multiple bits are set then MSB has highest priority. */ 202 203 extract_msb a4, a2 /* a4 = MSB of a2, a2 trashed */ 204 205 #ifdef XT_USE_SWPRI 206 /* Enable all interrupts at this level that are numerically higher 207 than the one we just selected, since they are treated as higher 208 priority. 209 */ 210 movi a3, \mask /* a3 = all interrupts at this level */ 211 add a2, a4, a4 /* a2 = a4 << 1 */ 212 addi a2, a2, -1 /* a2 = mask of 1's <= a4 bit */ 213 and a2, a2, a3 /* a2 = mask of all bits <= a4 at this level */ 214 movi a3, _xt_intdata 215 l32i a6, a3, 4 /* a6 = _xt_vpri_mask */ 216 neg a2, a2 217 addi a2, a2, -1 /* a2 = mask to apply */ 218 and a5, a6, a2 /* mask off all bits <= a4 bit */ 219 s32i a5, a3, 4 /* update _xt_vpri_mask */ 220 rsr a3, INTENABLE 221 and a3, a3, a2 /* mask off all bits <= a4 bit */ 222 wsr a3, INTENABLE 223 rsil a3, \level - 1 /* lower interrupt level by 1 */ 224 #endif 225 226 movi a3, XT_TIMER_INTEN /* a3 = timer interrupt bit */ 227 wsr a4, INTCLEAR /* clear sw or edge-triggered interrupt */ 228 beq a3, a4, 7f /* if timer interrupt then skip table */ 229 230 find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */ 231 232 movi a4, _xt_interrupt_table 233 addx8 a3, a3, a4 /* a3 = address of interrupt table entry */ 234 l32i a4, a3, XIE_HANDLER /* a4 = handler address */ 235 #ifdef __XTENSA_CALL0_ABI__ 236 mov a12, a6 /* save in callee-saved reg */ 237 l32i a2, a3, XIE_ARG /* a2 = handler arg */ 238 callx0 a4 /* call handler */ 239 mov a2, a12 240 #else 241 mov a2, a6 /* save in windowed reg */ 242 l32i a6, a3, XIE_ARG /* a6 = handler arg */ 243 callx4 a4 /* call handler */ 244 #endif 245 246 #ifdef XT_USE_SWPRI 247 j 8f 248 #else 249 j .L_xt_user_int_&level& /* check for more interrupts */ 250 #endif 251 2527: 253 254 .ifeq XT_TIMER_INTPRI - \level 255.L_xt_user_int_timer_&level&: 256 /* 257 Interrupt handler for the RTOS tick timer if at this level. 258 We'll be reading the interrupt state again after this call 259 so no need to preserve any registers except a6 (vpri_mask). 260 */ 261 262 #ifdef __XTENSA_CALL0_ABI__ 263 mov a12, a6 264 call0 XT_RTOS_TIMER_INT 265 mov a2, a12 266 #else 267 mov a2, a6 268 call4 XT_RTOS_TIMER_INT 269 #endif 270 .endif 271 272 #ifdef XT_USE_SWPRI 273 j 8f 274 #else 275 j .L_xt_user_int_&level& /* check for more interrupts */ 276 #endif 277 278 #ifdef XT_USE_SWPRI 2798: 280 /* Restore old value of _xt_vpri_mask from a2. Also update INTENABLE from 281 virtual _xt_intenable which _could_ have changed during interrupt 282 processing. */ 283 284 movi a3, _xt_intdata 285 l32i a4, a3, 0 /* a4 = _xt_intenable */ 286 s32i a2, a3, 4 /* update _xt_vpri_mask */ 287 and a4, a4, a2 /* a4 = masked intenable */ 288 wsr a4, INTENABLE /* update INTENABLE */ 289 #endif 290 2919: 292 /* done */ 293 294 .endm 295 296 297/* 298-------------------------------------------------------------------------------- 299 Panic handler. 300 Should be reached by call0 (preferable) or jump only. If call0, a0 says where 301 from. If on simulator, display panic message and abort, else loop indefinitely. 302-------------------------------------------------------------------------------- 303*/ 304 305 .text 306 .global _xt_panic 307 .type _xt_panic,@function 308 .align 4 309 .literal_position 310 311_xt_panic: 312 #ifdef XT_SIMULATOR 313 addi a4, a0, -3 /* point to call0 */ 314 movi a3, _xt_panic_message 315 movi a2, SYS_log_msg 316 simcall 317 movi a2, SYS_gdb_abort 318 simcall 319 #else 320 rsil a2, XCHAL_EXCM_LEVEL /* disable all low & med ints */ 3211: j 1b /* loop infinitely */ 322 #endif 323 324 .section .rodata, "a" 325 .align 4 326 327_xt_panic_message: 328 .string "\n*** _xt_panic() was called from 0x%08x or jumped to. ***\n" 329 330 331/* 332-------------------------------------------------------------------------------- 333 Hooks to dynamically install handlers for exceptions and interrupts. 334 Allows automated regression frameworks to install handlers per test. 335 Consists of an array of function pointers indexed by interrupt level, 336 with index 0 containing the entry for user exceptions. 337 Initialized with all 0s, meaning no handler is installed at each level. 338 See comment in xtensa_rtos.h for more details. 339-------------------------------------------------------------------------------- 340*/ 341 342 #ifdef XT_INTEXC_HOOKS 343 .data 344 .global _xt_intexc_hooks 345 .type _xt_intexc_hooks,@object 346 .align 4 347 348_xt_intexc_hooks: 349 .fill XT_INTEXC_HOOK_NUM, 4, 0 350 #endif 351 352 353/* 354-------------------------------------------------------------------------------- 355 EXCEPTION AND LEVEL 1 INTERRUPT VECTORS AND LOW LEVEL HANDLERS 356 (except window exception vectors). 357 358 Each vector goes at a predetermined location according to the Xtensa 359 hardware configuration, which is ensured by its placement in a special 360 section known to the Xtensa linker support package (LSP). It performs 361 the minimum necessary before jumping to the handler in the .text section. 362 363 The corresponding handler goes in the normal .text section. It sets up 364 the appropriate stack frame, saves a few vector-specific registers and 365 calls XT_RTOS_INT_ENTER to save the rest of the interrupted context 366 and enter the RTOS, then sets up a C environment. It then calls the 367 user's interrupt handler code (which may be coded in C) and finally 368 calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling. 369 370 While XT_RTOS_INT_EXIT does not return directly to the interruptee, 371 eventually the RTOS scheduler will want to dispatch the interrupted 372 task or handler. The scheduler will return to the exit point that was 373 saved in the interrupt stack frame at XT_STK_EXIT. 374-------------------------------------------------------------------------------- 375*/ 376 377 378/* 379-------------------------------------------------------------------------------- 380Debug Exception. 381-------------------------------------------------------------------------------- 382*/ 383 384#if XCHAL_HAVE_DEBUG 385 386 .begin literal_prefix .DebugExceptionVector 387 .section .DebugExceptionVector.text, "ax" 388 .global _DebugExceptionVector 389 .align 4 390 .literal_position 391 392_DebugExceptionVector: 393 394 #ifdef XT_SIMULATOR 395 /* 396 In the simulator, let the debugger (if any) handle the debug exception, 397 or simply stop the simulation: 398 */ 399 wsr a2, EXCSAVE+XCHAL_DEBUGLEVEL /* save a2 where sim expects it */ 400 movi a2, SYS_gdb_enter_sktloop 401 simcall /* have ISS handle debug exc. */ 402 #elif 0 /* change condition to 1 to use the HAL minimal debug handler */ 403 wsr a3, EXCSAVE+XCHAL_DEBUGLEVEL 404 movi a3, xthal_debugexc_defhndlr_nw /* use default debug handler */ 405 jx a3 406 #else 407 wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* save original a0 somewhere */ 408 call0 _xt_panic /* does not return */ 409 rfi XCHAL_DEBUGLEVEL /* make a0 point here not later */ 410 #endif 411 412 .end literal_prefix 413 414#endif 415 416/* 417-------------------------------------------------------------------------------- 418Double Exception. 419Double exceptions are not a normal occurrence. They indicate a bug of some kind. 420-------------------------------------------------------------------------------- 421*/ 422 423#ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR 424 425 .begin literal_prefix .DoubleExceptionVector 426 .section .DoubleExceptionVector.text, "ax" 427 .global _DoubleExceptionVector 428 .align 4 429 .literal_position 430 431_DoubleExceptionVector: 432 433 #if XCHAL_HAVE_DEBUG 434 break 1, 4 /* unhandled double exception */ 435 #endif 436 call0 _xt_panic /* does not return */ 437 rfde /* make a0 point here not later */ 438 439 .end literal_prefix 440 441#endif /* XCHAL_DOUBLEEXC_VECTOR_VADDR */ 442 443/* 444-------------------------------------------------------------------------------- 445Kernel Exception (including Level 1 Interrupt from kernel mode). 446-------------------------------------------------------------------------------- 447*/ 448 449 .begin literal_prefix .KernelExceptionVector 450 .section .KernelExceptionVector.text, "ax" 451 .global _KernelExceptionVector 452 .align 4 453 .literal_position 454 455_KernelExceptionVector: 456 457 wsr a0, EXCSAVE_1 /* preserve a0 */ 458 call0 _xt_kernel_exc /* kernel exception handler */ 459 /* never returns here - call0 is used as a jump (see note at top) */ 460 461 .end literal_prefix 462 463 .text 464 .align 4 465 466_xt_kernel_exc: 467 #if XCHAL_HAVE_DEBUG 468 break 1, 0 /* unhandled kernel exception */ 469 #endif 470 call0 _xt_panic /* does not return */ 471 rfe /* make a0 point here not there */ 472 473 474/* 475-------------------------------------------------------------------------------- 476User Exception (including Level 1 Interrupt from user mode). 477-------------------------------------------------------------------------------- 478*/ 479 480 .begin literal_prefix .UserExceptionVector 481 .section .UserExceptionVector.text, "ax" 482 .global _UserExceptionVector 483 .type _UserExceptionVector,@function 484 .align 4 485 .literal_position 486 487_UserExceptionVector: 488 489 wsr a0, EXCSAVE_1 /* preserve a0 */ 490 call0 _xt_user_exc /* user exception handler */ 491 /* never returns here - call0 is used as a jump (see note at top) */ 492 493 .end literal_prefix 494 495/* 496-------------------------------------------------------------------------------- 497 Insert some waypoints for jumping beyond the signed 8-bit range of 498 conditional branch instructions, so the conditional branchces to specific 499 exception handlers are not taken in the mainline. Saves some cycles in the 500 mainline. 501-------------------------------------------------------------------------------- 502*/ 503 504 .text 505 506 #if XCHAL_HAVE_WINDOWED 507 .align 4 508_xt_to_alloca_exc: 509 call0 _xt_alloca_exc /* in window vectors section */ 510 /* never returns here - call0 is used as a jump (see note at top) */ 511 #endif 512 513 .align 4 514_xt_to_syscall_exc: 515 call0 _xt_syscall_exc 516 /* never returns here - call0 is used as a jump (see note at top) */ 517 518 #if XCHAL_CP_NUM > 0 519 .align 4 520_xt_to_coproc_exc: 521 call0 _xt_coproc_exc 522 /* never returns here - call0 is used as a jump (see note at top) */ 523 #endif 524 525 526/* 527-------------------------------------------------------------------------------- 528 User exception handler. 529-------------------------------------------------------------------------------- 530*/ 531 532 .type _xt_user_exc,@function 533 .align 4 534 535_xt_user_exc: 536 537 /* If level 1 interrupt then jump to the dispatcher */ 538 rsr a0, EXCCAUSE 539 beqi a0, EXCCAUSE_LEVEL1INTERRUPT, _xt_lowint1 540 541 /* Handle any coprocessor exceptions. Rely on the fact that exception 542 numbers above EXCCAUSE_CP0_DISABLED all relate to the coprocessors. 543 */ 544 #if XCHAL_CP_NUM > 0 545 bgeui a0, EXCCAUSE_CP0_DISABLED, _xt_to_coproc_exc 546 #endif 547 548 /* Handle alloca and syscall exceptions */ 549 #if XCHAL_HAVE_WINDOWED 550 beqi a0, EXCCAUSE_ALLOCA, _xt_to_alloca_exc 551 #endif 552 beqi a0, EXCCAUSE_SYSCALL, _xt_to_syscall_exc 553 554 /* Handle all other exceptions. All can have user-defined handlers. */ 555 /* NOTE: we'll stay on the user stack for exception handling. */ 556 557 /* Allocate exception frame and save minimal context. */ 558 mov a0, sp 559 addi sp, sp, -XT_STK_FRMSZ 560 s32i a0, sp, XT_STK_A1 561 #if XCHAL_HAVE_WINDOWED 562 s32e a0, sp, -12 /* for debug backtrace */ 563 #endif 564 rsr a0, PS /* save interruptee's PS */ 565 s32i a0, sp, XT_STK_PS 566 rsr a0, EPC_1 /* save interruptee's PC */ 567 s32i a0, sp, XT_STK_PC 568 rsr a0, EXCSAVE_1 /* save interruptee's a0 */ 569 s32i a0, sp, XT_STK_A0 570 #if XCHAL_HAVE_WINDOWED 571 s32e a0, sp, -16 /* for debug backtrace */ 572 #endif 573 s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ 574 s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ 575 call0 _xt_context_save 576 577 /* Save exc cause and vaddr into exception frame */ 578 rsr a0, EXCCAUSE 579 s32i a0, sp, XT_STK_EXCCAUSE 580 rsr a0, EXCVADDR 581 s32i a0, sp, XT_STK_EXCVADDR 582 583 /* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */ 584 #ifdef __XTENSA_CALL0_ABI__ 585 movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM 586 #else 587 movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE 588 #endif 589 wsr a0, PS 590 591 #ifdef XT_DEBUG_BACKTRACE 592 #ifndef __XTENSA_CALL0_ABI__ 593 rsr a0, EPC_1 /* return address for debug backtrace */ 594 movi a5, 0xC0000000 /* constant with top 2 bits set (call size) */ 595 rsync /* wait for WSR.PS to complete */ 596 or a0, a0, a5 /* set top 2 bits */ 597 addx2 a0, a5, a0 /* clear top bit -- thus simulating call4 size */ 598 #else 599 rsync /* wait for WSR.PS to complete */ 600 #endif 601 #endif 602 603 rsr a2, EXCCAUSE /* recover exc cause */ 604 605 #ifdef XT_INTEXC_HOOKS 606 /* 607 Call exception hook to pre-handle exceptions (if installed). 608 Pass EXCCAUSE in a2, and check result in a2 (if -1, skip default handling). 609 */ 610 movi a4, _xt_intexc_hooks 611 l32i a4, a4, 0 /* user exception hook index 0 */ 612 beqz a4, 1f 613.Ln_xt_user_exc_call_hook: 614 #ifdef __XTENSA_CALL0_ABI__ 615 callx0 a4 616 beqi a2, -1, .L_xt_user_done 617 #else 618 mov a6, a2 619 callx4 a4 620 beqi a6, -1, .L_xt_user_done 621 mov a2, a6 622 #endif 6231: 624 #endif 625 626 rsr a2, EXCCAUSE /* recover exc cause */ 627 movi a3, _xt_exception_table 628 addx4 a4, a2, a3 /* a4 = address of exception table entry */ 629 l32i a4, a4, 0 /* a4 = handler address */ 630 #ifdef __XTENSA_CALL0_ABI__ 631 mov a2, sp /* a2 = pointer to exc frame */ 632 callx0 a4 /* call handler */ 633 #else 634 mov a6, sp /* a6 = pointer to exc frame */ 635 callx4 a4 /* call handler */ 636 #endif 637 638.L_xt_user_done: 639 640 /* Restore context and return */ 641 call0 _xt_context_restore 642 l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ 643 wsr a0, PS 644 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ 645 wsr a0, EPC_1 646 l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ 647 l32i sp, sp, XT_STK_A1 /* remove exception frame */ 648 rsync /* ensure PS and EPC written */ 649 rfe /* PS.EXCM is cleared */ 650 651 652/* 653-------------------------------------------------------------------------------- 654 Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT 655 on entry and used to return to a thread or interrupted interrupt handler. 656-------------------------------------------------------------------------------- 657*/ 658 659 .global _xt_user_exit 660 .type _xt_user_exit,@function 661 .align 4 662_xt_user_exit: 663 l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ 664 wsr a0, PS 665 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ 666 wsr a0, EPC_1 667 l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ 668 l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ 669 rsync /* ensure PS and EPC written */ 670 rfe /* PS.EXCM is cleared */ 671 672 673/* 674-------------------------------------------------------------------------------- 675Syscall Exception Handler (jumped to from User Exception Handler). 676Syscall 0 is required to spill the register windows (no-op in Call 0 ABI). 677Only syscall 0 is handled here. Other syscalls return -1 to caller in a2. 678-------------------------------------------------------------------------------- 679*/ 680 681 .text 682 .type _xt_syscall_exc,@function 683 .align 4 684_xt_syscall_exc: 685 686 #ifdef __XTENSA_CALL0_ABI__ 687 /* 688 Save minimal regs for scratch. Syscall 0 does nothing in Call0 ABI. 689 Use a minimal stack frame (16B) to save A2 & A3 for scratch. 690 PS.EXCM could be cleared here, but unlikely to improve worst-case latency. 691 rsr a0, PS 692 addi a0, a0, -PS_EXCM_MASK 693 wsr a0, PS 694 */ 695 addi sp, sp, -16 696 s32i a2, sp, 8 697 s32i a3, sp, 12 698 #else /* Windowed ABI */ 699 /* 700 Save necessary context and spill the register windows. 701 PS.EXCM is still set and must remain set until after the spill. 702 Reuse context save function though it saves more than necessary. 703 For this reason, a full interrupt stack frame is allocated. 704 */ 705 addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ 706 s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ 707 s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ 708 call0 _xt_context_save 709 #endif 710 711 /* 712 Grab the interruptee's PC and skip over the 'syscall' instruction. 713 If it's at the end of a zero-overhead loop and it's not on the last 714 iteration, decrement loop counter and skip to beginning of loop. 715 */ 716 rsr a2, EPC_1 /* a2 = PC of 'syscall' */ 717 addi a3, a2, 3 /* ++PC */ 718 #if XCHAL_HAVE_LOOPS 719 rsr a0, LEND /* if (PC == LEND */ 720 bne a3, a0, 1f 721 rsr a0, LCOUNT /* && LCOUNT != 0) */ 722 beqz a0, 1f /* { */ 723 addi a0, a0, -1 /* --LCOUNT */ 724 rsr a3, LBEG /* PC = LBEG */ 725 wsr a0, LCOUNT /* } */ 726 #endif 7271: wsr a3, EPC_1 /* update PC */ 728 729 /* Restore interruptee's context and return from exception. */ 730 #ifdef __XTENSA_CALL0_ABI__ 731 l32i a2, sp, 8 732 l32i a3, sp, 12 733 addi sp, sp, 16 734 #else 735 call0 _xt_context_restore 736 addi sp, sp, XT_STK_FRMSZ 737 #endif 738 movi a0, -1 739 movnez a2, a0, a2 /* return -1 if not syscall 0 */ 740 rsr a0, EXCSAVE_1 741 rfe 742 743/* 744-------------------------------------------------------------------------------- 745Co-Processor Exception Handler (jumped to from User Exception Handler). 746These exceptions are generated by co-processor instructions, which are only 747allowed in thread code (not in interrupts or kernel code). This restriction is 748deliberately imposed to reduce the burden of state-save/restore in interrupts. 749-------------------------------------------------------------------------------- 750*/ 751#if XCHAL_CP_NUM > 0 752 753 .section .rodata, "a" 754 755/* Offset to CP n save area in thread's CP save area. */ 756 .global _xt_coproc_sa_offset 757 .type _xt_coproc_sa_offset,@object 758 .align 16 /* minimize crossing cache boundaries */ 759_xt_coproc_sa_offset: 760 .word XT_CP0_SA, XT_CP1_SA, XT_CP2_SA, XT_CP3_SA 761 .word XT_CP4_SA, XT_CP5_SA, XT_CP6_SA, XT_CP7_SA 762 763/* Bitmask for CP n's CPENABLE bit. */ 764 .type _xt_coproc_mask,@object 765 .align 16,,8 /* try to keep it all in one cache line */ 766 .set i, 0 767_xt_coproc_mask: 768 .rept XCHAL_CP_MAX 769 .long (i<<16) | (1<<i) // upper 16-bits = i, lower = bitmask 770 .set i, i+1 771 .endr 772 773 .data 774 775/* Owner thread of CP n, identified by thread's CP save area (0 = unowned). */ 776 .global _xt_coproc_owner_sa 777 .type _xt_coproc_owner_sa,@object 778 .align 16,,XCHAL_CP_MAX<<2 /* minimize crossing cache boundaries */ 779_xt_coproc_owner_sa: 780 .space XCHAL_CP_MAX << 2 781 782 .text 783 784 785 .align 4 786.L_goto_invalid: 787 j .L_xt_coproc_invalid /* not in a thread (invalid) */ 788 .align 4 789.L_goto_done: 790 j .L_xt_coproc_done 791 792 793/* 794-------------------------------------------------------------------------------- 795 Coprocessor exception handler. 796 At entry, only a0 has been saved (in EXCSAVE_1). 797-------------------------------------------------------------------------------- 798*/ 799 800 .type _xt_coproc_exc,@function 801 .align 4 802 803_xt_coproc_exc: 804 805 /* Allocate interrupt stack frame and save minimal context. */ 806 mov a0, sp /* sp == a1 */ 807 addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ 808 s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ 809 #if XCHAL_HAVE_WINDOWED 810 s32e a0, sp, -12 /* for debug backtrace */ 811 #endif 812 rsr a0, PS /* save interruptee's PS */ 813 s32i a0, sp, XT_STK_PS 814 rsr a0, EPC_1 /* save interruptee's PC */ 815 s32i a0, sp, XT_STK_PC 816 rsr a0, EXCSAVE_1 /* save interruptee's a0 */ 817 s32i a0, sp, XT_STK_A0 818 #if XCHAL_HAVE_WINDOWED 819 s32e a0, sp, -16 /* for debug backtrace */ 820 #endif 821 movi a0, _xt_user_exit /* save exit point for dispatch */ 822 s32i a0, sp, XT_STK_EXIT 823 824 rsr a0, EXCCAUSE 825 s32i a5, sp, XT_STK_A5 /* save a5 */ 826 addi a5, a0, -EXCCAUSE_CP0_DISABLED /* a5 = CP index */ 827 828 /* Save a few more of interruptee's registers (a5 was already saved). */ 829 s32i a2, sp, XT_STK_A2 830 s32i a3, sp, XT_STK_A3 831 s32i a4, sp, XT_STK_A4 832 s32i a15, sp, XT_STK_A15 833 834 /* Get co-processor state save area of new owner thread. */ 835 call0 XT_RTOS_CP_STATE /* a15 = new owner's save area */ 836 beqz a15, .L_goto_invalid /* not in a thread (invalid) */ 837 838 /* Enable the co-processor's bit in CPENABLE. */ 839 movi a0, _xt_coproc_mask 840 rsr a4, CPENABLE /* a4 = CPENABLE */ 841 addx4 a0, a5, a0 /* a0 = &_xt_coproc_mask[n] */ 842 l32i a0, a0, 0 /* a0 = (n << 16) | (1 << n) */ 843 movi a3, _xt_coproc_owner_sa /* (placed here for load slot) */ 844 extui a2, a0, 0, 16 /* coprocessor bitmask portion */ 845 or a4, a4, a2 /* a4 = CPENABLE | (1 << n) */ 846 wsr a4, CPENABLE 847 848 /* Get old coprocessor owner thread (save area ptr) and assign new one. */ 849 addx4 a3, a5, a3 /* a3 = &_xt_coproc_owner_sa[n] */ 850 l32i a2, a3, 0 /* a2 = old owner's save area */ 851 s32i a15, a3, 0 /* _xt_coproc_owner_sa[n] = new */ 852 rsync /* ensure wsr.CPENABLE is complete */ 853 854 /* Only need to context switch if new owner != old owner. */ 855 beq a15, a2, .L_goto_done /* new owner == old, we're done */ 856 857 /* If no old owner then nothing to save. */ 858 beqz a2, .L_check_new 859 860 /* If old owner not actively using CP then nothing to save. */ 861 l16ui a4, a2, XT_CPENABLE /* a4 = old owner's CPENABLE */ 862 bnone a4, a0, .L_check_new /* old owner not using CP */ 863 864.L_save_old: 865 /* Save old owner's coprocessor state. */ 866 867 movi a5, _xt_coproc_sa_offset 868 869 /* Mark old owner state as no longer active (CPENABLE bit n clear). */ 870 xor a4, a4, a0 /* clear CP bit in CPENABLE */ 871 s16i a4, a2, XT_CPENABLE /* update old owner's CPENABLE */ 872 873 extui a4, a0, 16, 5 /* a4 = CP index = n */ 874 addx4 a5, a4, a5 /* a5 = &_xt_coproc_sa_offset[n] */ 875 876 /* Mark old owner state as saved (CPSTORED bit n set). */ 877 l16ui a4, a2, XT_CPSTORED /* a4 = old owner's CPSTORED */ 878 l32i a5, a5, 0 /* a5 = XT_CP[n]_SA offset */ 879 or a4, a4, a0 /* set CP in old owner's CPSTORED */ 880 s16i a4, a2, XT_CPSTORED /* update old owner's CPSTORED */ 881 l32i a2, a2, XT_CP_ASA /* ptr to actual (aligned) save area */ 882 extui a3, a0, 16, 5 /* a3 = CP index = n */ 883 add a2, a2, a5 /* a2 = old owner's area for CP n */ 884 885 /* 886 The config-specific HAL macro invoked below destroys a2-5, preserves a0-1. 887 It is theoretically possible for Xtensa processor designers to write TIE 888 that causes more address registers to be affected, but it is generally 889 unlikely. If that ever happens, more registers needs to be saved/restored 890 around this macro invocation, and the value in a15 needs to be recomputed. 891 */ 892 xchal_cpi_store_funcbody 893 894.L_check_new: 895 /* Check if any state has to be restored for new owner. */ 896 /* NOTE: a15 = new owner's save area, cannot be zero when we get here. */ 897 898 l16ui a3, a15, XT_CPSTORED /* a3 = new owner's CPSTORED */ 899 movi a4, _xt_coproc_sa_offset 900 bnone a3, a0, .L_check_cs /* full CP not saved, check callee-saved */ 901 xor a3, a3, a0 /* CPSTORED bit is set, clear it */ 902 s16i a3, a15, XT_CPSTORED /* update new owner's CPSTORED */ 903 904 /* Adjust new owner's save area pointers to area for CP n. */ 905 extui a3, a0, 16, 5 /* a3 = CP index = n */ 906 addx4 a4, a3, a4 /* a4 = &_xt_coproc_sa_offset[n] */ 907 l32i a4, a4, 0 /* a4 = XT_CP[n]_SA */ 908 l32i a5, a15, XT_CP_ASA /* ptr to actual (aligned) save area */ 909 add a2, a4, a5 /* a2 = new owner's area for CP */ 910 911 /* 912 The config-specific HAL macro invoked below destroys a2-5, preserves a0-1. 913 It is theoretically possible for Xtensa processor designers to write TIE 914 that causes more address registers to be affected, but it is generally 915 unlikely. If that ever happens, more registers needs to be saved/restored 916 around this macro invocation. 917 */ 918 xchal_cpi_load_funcbody 919 920 /* Restore interruptee's saved registers. */ 921 /* Can omit rsync for wsr.CPENABLE here because _xt_user_exit does it. */ 922.L_xt_coproc_done: 923 l32i a15, sp, XT_STK_A15 924 l32i a5, sp, XT_STK_A5 925 l32i a4, sp, XT_STK_A4 926 l32i a3, sp, XT_STK_A3 927 l32i a2, sp, XT_STK_A2 928 call0 _xt_user_exit /* return via exit dispatcher */ 929 /* Never returns here - call0 is used as a jump (see note at top) */ 930 931.L_check_cs: 932 /* a0 = CP mask in low bits, a15 = new owner's save area */ 933 l16ui a2, a15, XT_CP_CS_ST /* a2 = mask of CPs saved */ 934 bnone a2, a0, .L_xt_coproc_done /* if no match then done */ 935 and a2, a2, a0 /* a2 = which CPs to restore */ 936 extui a2, a2, 0, 8 /* extract low 8 bits */ 937 s32i a6, sp, XT_STK_A6 /* save extra needed regs */ 938 s32i a7, sp, XT_STK_A7 939 s32i a13, sp, XT_STK_A13 940 s32i a14, sp, XT_STK_A14 941 call0 _xt_coproc_restorecs /* restore CP registers */ 942 l32i a6, sp, XT_STK_A6 /* restore saved registers */ 943 l32i a7, sp, XT_STK_A7 944 l32i a13, sp, XT_STK_A13 945 l32i a14, sp, XT_STK_A14 946 j .L_xt_coproc_done 947 948 /* Co-processor exception occurred outside a thread (not supported). */ 949.L_xt_coproc_invalid: 950 #if XCHAL_HAVE_DEBUG 951 break 1, 1 /* unhandled user exception */ 952 #endif 953 call0 _xt_panic /* not in a thread (invalid) */ 954 /* never returns */ 955 956 957#endif /* XCHAL_CP_NUM */ 958 959 960/* 961------------------------------------------------------------------------------- 962 Level 1 interrupt dispatch. Assumes stack frame has not been allocated yet. 963------------------------------------------------------------------------------- 964*/ 965 966 .text 967 .type _xt_lowint1,@function 968 .align 4 969 970_xt_lowint1: 971 mov a0, sp /* sp == a1 */ 972 addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ 973 s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ 974 rsr a0, PS /* save interruptee's PS */ 975 s32i a0, sp, XT_STK_PS 976 rsr a0, EPC_1 /* save interruptee's PC */ 977 s32i a0, sp, XT_STK_PC 978 rsr a0, EXCSAVE_1 /* save interruptee's a0 */ 979 s32i a0, sp, XT_STK_A0 980 movi a0, _xt_user_exit /* save exit point for dispatch */ 981 s32i a0, sp, XT_STK_EXIT 982 983 /* Save rest of interrupt context and enter RTOS. */ 984 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ 985 986 /* !! We are now on the RTOS system stack !! */ 987 988 /* Set up PS for C, enable interrupts above this level and clear EXCM. */ 989 #ifdef __XTENSA_CALL0_ABI__ 990 movi a0, PS_INTLEVEL(1) | PS_UM 991 #else 992 movi a0, PS_INTLEVEL(1) | PS_UM | PS_WOE 993 #endif 994 wsr a0, PS 995 rsync 996 997 /* OK to call C code at this point, dispatch user ISRs */ 998 999 dispatch_c_isr 1 XCHAL_INTLEVEL1_MASK 1000 1001 /* Done handling interrupts, transfer control to OS */ 1002 call0 XT_RTOS_INT_EXIT /* does not return directly here */ 1003 1004 1005/* 1006------------------------------------------------------------------------------- 1007 MEDIUM PRIORITY (LEVEL 2+) INTERRUPT VECTORS AND LOW LEVEL HANDLERS. 1008 1009 Medium priority interrupts are by definition those with priority greater 1010 than 1 and not greater than XCHAL_EXCM_LEVEL. These are disabled by 1011 setting PS.EXCM and therefore can easily support a C environment for 1012 handlers in C, and interact safely with an RTOS. 1013 1014 Each vector goes at a predetermined location according to the Xtensa 1015 hardware configuration, which is ensured by its placement in a special 1016 section known to the Xtensa linker support package (LSP). It performs 1017 the minimum necessary before jumping to the handler in the .text section. 1018 1019 The corresponding handler goes in the normal .text section. It sets up 1020 the appropriate stack frame, saves a few vector-specific registers and 1021 calls XT_RTOS_INT_ENTER to save the rest of the interrupted context 1022 and enter the RTOS, then sets up a C environment. It then calls the 1023 user's interrupt handler code (which may be coded in C) and finally 1024 calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling. 1025 1026 While XT_RTOS_INT_EXIT does not return directly to the interruptee, 1027 eventually the RTOS scheduler will want to dispatch the interrupted 1028 task or handler. The scheduler will return to the exit point that was 1029 saved in the interrupt stack frame at XT_STK_EXIT. 1030------------------------------------------------------------------------------- 1031*/ 1032 1033#if XCHAL_EXCM_LEVEL >= 2 1034 1035 .begin literal_prefix .Level2InterruptVector 1036 .section .Level2InterruptVector.text, "ax" 1037 .global _Level2Vector 1038 .type _Level2Vector,@function 1039 .align 4 1040 .literal_position 1041 1042_Level2Vector: 1043 wsr a0, EXCSAVE_2 /* preserve a0 */ 1044 call0 _xt_medint2 /* load interrupt handler */ 1045 /* never returns here - call0 is used as a jump (see note at top) */ 1046 1047 .end literal_prefix 1048 1049 .text 1050 .type _xt_medint2,@function 1051 .align 4 1052_xt_medint2: 1053 mov a0, sp /* sp == a1 */ 1054 addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ 1055 s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ 1056 rsr a0, EPS_2 /* save interruptee's PS */ 1057 s32i a0, sp, XT_STK_PS 1058 rsr a0, EPC_2 /* save interruptee's PC */ 1059 s32i a0, sp, XT_STK_PC 1060 rsr a0, EXCSAVE_2 /* save interruptee's a0 */ 1061 s32i a0, sp, XT_STK_A0 1062 movi a0, _xt_medint2_exit /* save exit point for dispatch */ 1063 s32i a0, sp, XT_STK_EXIT 1064 1065 /* Save rest of interrupt context and enter RTOS. */ 1066 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ 1067 1068 /* !! We are now on the RTOS system stack !! */ 1069 1070 /* Set up PS for C, enable interrupts above this level and clear EXCM. */ 1071 #ifdef __XTENSA_CALL0_ABI__ 1072 movi a0, PS_INTLEVEL(2) | PS_UM 1073 #else 1074 movi a0, PS_INTLEVEL(2) | PS_UM | PS_WOE 1075 #endif 1076 wsr a0, PS 1077 rsync 1078 1079 /* OK to call C code at this point, dispatch user ISRs */ 1080 1081 dispatch_c_isr 2 XCHAL_INTLEVEL2_MASK 1082 1083 /* Done handling interrupts, transfer control to OS */ 1084 call0 XT_RTOS_INT_EXIT /* does not return directly here */ 1085 1086 /* 1087 Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT 1088 on entry and used to return to a thread or interrupted interrupt handler. 1089 */ 1090 .global _xt_medint2_exit 1091 .type _xt_medint2_exit,@function 1092 .align 4 1093_xt_medint2_exit: 1094 /* Restore only level-specific regs (the rest were already restored) */ 1095 l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ 1096 wsr a0, EPS_2 1097 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ 1098 wsr a0, EPC_2 1099 l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ 1100 l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ 1101 rsync /* ensure EPS and EPC written */ 1102 rfi 2 1103 1104#endif /* Level 2 */ 1105 1106#if XCHAL_EXCM_LEVEL >= 3 1107 1108 .begin literal_prefix .Level3InterruptVector 1109 .section .Level3InterruptVector.text, "ax" 1110 .global _Level3Vector 1111 .type _Level3Vector,@function 1112 .align 4 1113 .literal_position 1114 1115_Level3Vector: 1116 wsr a0, EXCSAVE_3 /* preserve a0 */ 1117 call0 _xt_medint3 /* load interrupt handler */ 1118 /* never returns here - call0 is used as a jump (see note at top) */ 1119 1120 .end literal_prefix 1121 1122 .text 1123 .type _xt_medint3,@function 1124 .align 4 1125_xt_medint3: 1126 mov a0, sp /* sp == a1 */ 1127 addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ 1128 s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ 1129 rsr a0, EPS_3 /* save interruptee's PS */ 1130 s32i a0, sp, XT_STK_PS 1131 rsr a0, EPC_3 /* save interruptee's PC */ 1132 s32i a0, sp, XT_STK_PC 1133 rsr a0, EXCSAVE_3 /* save interruptee's a0 */ 1134 s32i a0, sp, XT_STK_A0 1135 movi a0, _xt_medint3_exit /* save exit point for dispatch */ 1136 s32i a0, sp, XT_STK_EXIT 1137 1138 /* Save rest of interrupt context and enter RTOS. */ 1139 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ 1140 1141 /* !! We are now on the RTOS system stack !! */ 1142 1143 /* Set up PS for C, enable interrupts above this level and clear EXCM. */ 1144 #ifdef __XTENSA_CALL0_ABI__ 1145 movi a0, PS_INTLEVEL(3) | PS_UM 1146 #else 1147 movi a0, PS_INTLEVEL(3) | PS_UM | PS_WOE 1148 #endif 1149 wsr a0, PS 1150 rsync 1151 1152 /* OK to call C code at this point, dispatch user ISRs */ 1153 1154 dispatch_c_isr 3 XCHAL_INTLEVEL3_MASK 1155 1156 /* Done handling interrupts, transfer control to OS */ 1157 call0 XT_RTOS_INT_EXIT /* does not return directly here */ 1158 1159 /* 1160 Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT 1161 on entry and used to return to a thread or interrupted interrupt handler. 1162 */ 1163 .global _xt_medint3_exit 1164 .type _xt_medint3_exit,@function 1165 .align 4 1166_xt_medint3_exit: 1167 /* Restore only level-specific regs (the rest were already restored) */ 1168 l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ 1169 wsr a0, EPS_3 1170 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ 1171 wsr a0, EPC_3 1172 l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ 1173 l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ 1174 rsync /* ensure EPS and EPC written */ 1175 rfi 3 1176 1177#endif /* Level 3 */ 1178 1179#if XCHAL_EXCM_LEVEL >= 4 1180 1181 .begin literal_prefix .Level4InterruptVector 1182 .section .Level4InterruptVector.text, "ax" 1183 .global _Level4Vector 1184 .type _Level4Vector,@function 1185 .align 4 1186 .literal_position 1187 1188_Level4Vector: 1189 wsr a0, EXCSAVE_4 /* preserve a0 */ 1190 call0 _xt_medint4 /* load interrupt handler */ 1191 1192 .end literal_prefix 1193 1194 .text 1195 .type _xt_medint4,@function 1196 .align 4 1197_xt_medint4: 1198 mov a0, sp /* sp == a1 */ 1199 addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ 1200 s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ 1201 rsr a0, EPS_4 /* save interruptee's PS */ 1202 s32i a0, sp, XT_STK_PS 1203 rsr a0, EPC_4 /* save interruptee's PC */ 1204 s32i a0, sp, XT_STK_PC 1205 rsr a0, EXCSAVE_4 /* save interruptee's a0 */ 1206 s32i a0, sp, XT_STK_A0 1207 movi a0, _xt_medint4_exit /* save exit point for dispatch */ 1208 s32i a0, sp, XT_STK_EXIT 1209 1210 /* Save rest of interrupt context and enter RTOS. */ 1211 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ 1212 1213 /* !! We are now on the RTOS system stack !! */ 1214 1215 /* Set up PS for C, enable interrupts above this level and clear EXCM. */ 1216 #ifdef __XTENSA_CALL0_ABI__ 1217 movi a0, PS_INTLEVEL(4) | PS_UM 1218 #else 1219 movi a0, PS_INTLEVEL(4) | PS_UM | PS_WOE 1220 #endif 1221 wsr a0, PS 1222 rsync 1223 1224 /* OK to call C code at this point, dispatch user ISRs */ 1225 1226 dispatch_c_isr 4 XCHAL_INTLEVEL4_MASK 1227 1228 /* Done handling interrupts, transfer control to OS */ 1229 call0 XT_RTOS_INT_EXIT /* does not return directly here */ 1230 1231 /* 1232 Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT 1233 on entry and used to return to a thread or interrupted interrupt handler. 1234 */ 1235 .global _xt_medint4_exit 1236 .type _xt_medint4_exit,@function 1237 .align 4 1238_xt_medint4_exit: 1239 /* Restore only level-specific regs (the rest were already restored) */ 1240 l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ 1241 wsr a0, EPS_4 1242 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ 1243 wsr a0, EPC_4 1244 l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ 1245 l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ 1246 rsync /* ensure EPS and EPC written */ 1247 rfi 4 1248 1249#endif /* Level 4 */ 1250 1251#if XCHAL_EXCM_LEVEL >= 5 1252 1253 .begin literal_prefix .Level5InterruptVector 1254 .section .Level5InterruptVector.text, "ax" 1255 .global _Level5Vector 1256 .type _Level5Vector,@function 1257 .align 4 1258 .literal_position 1259 1260_Level5Vector: 1261 wsr a0, EXCSAVE_5 /* preserve a0 */ 1262 call0 _xt_medint5 /* load interrupt handler */ 1263 1264 .end literal_prefix 1265 1266 .text 1267 .type _xt_medint5,@function 1268 .align 4 1269_xt_medint5: 1270 mov a0, sp /* sp == a1 */ 1271 addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ 1272 s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ 1273 rsr a0, EPS_5 /* save interruptee's PS */ 1274 s32i a0, sp, XT_STK_PS 1275 rsr a0, EPC_5 /* save interruptee's PC */ 1276 s32i a0, sp, XT_STK_PC 1277 rsr a0, EXCSAVE_5 /* save interruptee's a0 */ 1278 s32i a0, sp, XT_STK_A0 1279 movi a0, _xt_medint5_exit /* save exit point for dispatch */ 1280 s32i a0, sp, XT_STK_EXIT 1281 1282 /* Save rest of interrupt context and enter RTOS. */ 1283 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ 1284 1285 /* !! We are now on the RTOS system stack !! */ 1286 1287 /* Set up PS for C, enable interrupts above this level and clear EXCM. */ 1288 #ifdef __XTENSA_CALL0_ABI__ 1289 movi a0, PS_INTLEVEL(5) | PS_UM 1290 #else 1291 movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE 1292 #endif 1293 wsr a0, PS 1294 rsync 1295 1296 /* OK to call C code at this point, dispatch user ISRs */ 1297 1298 dispatch_c_isr 5 XCHAL_INTLEVEL5_MASK 1299 1300 /* Done handling interrupts, transfer control to OS */ 1301 call0 XT_RTOS_INT_EXIT /* does not return directly here */ 1302 1303 /* 1304 Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT 1305 on entry and used to return to a thread or interrupted interrupt handler. 1306 */ 1307 .global _xt_medint5_exit 1308 .type _xt_medint5_exit,@function 1309 .align 4 1310_xt_medint5_exit: 1311 /* Restore only level-specific regs (the rest were already restored) */ 1312 l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ 1313 wsr a0, EPS_5 1314 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ 1315 wsr a0, EPC_5 1316 l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ 1317 l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ 1318 rsync /* ensure EPS and EPC written */ 1319 rfi 5 1320 1321#endif /* Level 5 */ 1322 1323#if XCHAL_EXCM_LEVEL >= 6 1324 1325 .begin literal_prefix .Level6InterruptVector 1326 .section .Level6InterruptVector.text, "ax" 1327 .global _Level6Vector 1328 .type _Level6Vector,@function 1329 .align 4 1330 .literal_position 1331 1332_Level6Vector: 1333 wsr a0, EXCSAVE_6 /* preserve a0 */ 1334 call0 _xt_medint6 /* load interrupt handler */ 1335 1336 .end literal_prefix 1337 1338 .text 1339 .type _xt_medint6,@function 1340 .align 4 1341_xt_medint6: 1342 mov a0, sp /* sp == a1 */ 1343 addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ 1344 s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ 1345 rsr a0, EPS_6 /* save interruptee's PS */ 1346 s32i a0, sp, XT_STK_PS 1347 rsr a0, EPC_6 /* save interruptee's PC */ 1348 s32i a0, sp, XT_STK_PC 1349 rsr a0, EXCSAVE_6 /* save interruptee's a0 */ 1350 s32i a0, sp, XT_STK_A0 1351 movi a0, _xt_medint6_exit /* save exit point for dispatch */ 1352 s32i a0, sp, XT_STK_EXIT 1353 1354 /* Save rest of interrupt context and enter RTOS. */ 1355 call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ 1356 1357 /* !! We are now on the RTOS system stack !! */ 1358 1359 /* Set up PS for C, enable interrupts above this level and clear EXCM. */ 1360 #ifdef __XTENSA_CALL0_ABI__ 1361 movi a0, PS_INTLEVEL(6) | PS_UM 1362 #else 1363 movi a0, PS_INTLEVEL(6) | PS_UM | PS_WOE 1364 #endif 1365 wsr a0, PS 1366 rsync 1367 1368 /* OK to call C code at this point, dispatch user ISRs */ 1369 1370 dispatch_c_isr 6 XCHAL_INTLEVEL6_MASK 1371 1372 /* Done handling interrupts, transfer control to OS */ 1373 call0 XT_RTOS_INT_EXIT /* does not return directly here */ 1374 1375 /* 1376 Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT 1377 on entry and used to return to a thread or interrupted interrupt handler. 1378 */ 1379 .global _xt_medint6_exit 1380 .type _xt_medint6_exit,@function 1381 .align 4 1382_xt_medint6_exit: 1383 /* Restore only level-specific regs (the rest were already restored) */ 1384 l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ 1385 wsr a0, EPS_6 1386 l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ 1387 wsr a0, EPC_6 1388 l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ 1389 l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ 1390 rsync /* ensure EPS and EPC written */ 1391 rfi 6 1392 1393#endif /* Level 6 */ 1394 1395 1396/******************************************************************************* 1397 1398HIGH PRIORITY (LEVEL > XCHAL_EXCM_LEVEL) INTERRUPT VECTORS AND HANDLERS 1399 1400High priority interrupts are by definition those with priorities greater 1401than XCHAL_EXCM_LEVEL. This includes non-maskable (NMI). High priority 1402interrupts cannot interact with the RTOS, that is they must save all regs 1403they use and not call any RTOS function. 1404 1405A further restriction imposed by the Xtensa windowed architecture is that 1406high priority interrupts must not modify the stack area even logically 1407"above" the top of the interrupted stack (they need to provide their 1408own stack or static save area). 1409 1410Cadence Design Systems recommends high priority interrupt handlers be coded in assembly 1411and used for purposes requiring very short service times. 1412 1413Here are templates for high priority (level 2+) interrupt vectors. 1414They assume only one interrupt per level to avoid the burden of identifying 1415which interrupts at this level are pending and enabled. This allows for 1416minimum latency and avoids having to save/restore a2 in addition to a0. 1417If more than one interrupt per high priority level is configured, this burden 1418is on the handler which in any case must provide a way to save and restore 1419registers it uses without touching the interrupted stack. 1420 1421Each vector goes at a predetermined location according to the Xtensa 1422hardware configuration, which is ensured by its placement in a special 1423section known to the Xtensa linker support package (LSP). It performs 1424the minimum necessary before jumping to the handler in the .text section. 1425 1426*******************************************************************************/ 1427 1428/* 1429Currently only shells for high priority interrupt handlers are provided 1430here. However a template and example can be found in the Cadence Design Systems tools 1431documentation: "Microprocessor Programmer's Guide". 1432*/ 1433 1434#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2 1435 1436 .begin literal_prefix .Level2InterruptVector 1437 .section .Level2InterruptVector.text, "ax" 1438 .global _Level2Vector 1439 .type _Level2Vector,@function 1440 .align 4 1441_Level2Vector: 1442 wsr a0, EXCSAVE_2 /* preserve a0 */ 1443 call0 _xt_highint2 /* load interrupt handler */ 1444 1445 .end literal_prefix 1446 1447 .text 1448 .type _xt_highint2,@function 1449 .align 4 1450_xt_highint2: 1451 1452 #ifdef XT_INTEXC_HOOKS 1453 /* Call interrupt hook if present to (pre)handle interrupts. */ 1454 movi a0, _xt_intexc_hooks 1455 l32i a0, a0, 2<<2 1456 beqz a0, 1f 1457.Ln_xt_highint2_call_hook: 1458 callx0 a0 /* must NOT disturb stack! */ 14591: 1460 #endif 1461 1462 /* USER_EDIT: 1463 ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE. 1464 */ 1465 1466 .align 4 1467.L_xt_highint2_exit: 1468 rsr a0, EXCSAVE_2 /* restore a0 */ 1469 rfi 2 1470 1471#endif /* Level 2 */ 1472 1473#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3 1474 1475 .begin literal_prefix .Level3InterruptVector 1476 .section .Level3InterruptVector.text, "ax" 1477 .global _Level3Vector 1478 .type _Level3Vector,@function 1479 .align 4 1480_Level3Vector: 1481 wsr a0, EXCSAVE_3 /* preserve a0 */ 1482 call0 _xt_highint3 /* load interrupt handler */ 1483 /* never returns here - call0 is used as a jump (see note at top) */ 1484 1485 .end literal_prefix 1486 1487 .text 1488 .type _xt_highint3,@function 1489 .align 4 1490_xt_highint3: 1491 1492 #ifdef XT_INTEXC_HOOKS 1493 /* Call interrupt hook if present to (pre)handle interrupts. */ 1494 movi a0, _xt_intexc_hooks 1495 l32i a0, a0, 3<<2 1496 beqz a0, 1f 1497.Ln_xt_highint3_call_hook: 1498 callx0 a0 /* must NOT disturb stack! */ 14991: 1500 #endif 1501 1502 /* USER_EDIT: 1503 ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE. 1504 */ 1505 1506 .align 4 1507.L_xt_highint3_exit: 1508 rsr a0, EXCSAVE_3 /* restore a0 */ 1509 rfi 3 1510 1511#endif /* Level 3 */ 1512 1513#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4 1514 1515 .begin literal_prefix .Level4InterruptVector 1516 .section .Level4InterruptVector.text, "ax" 1517 .global _Level4Vector 1518 .type _Level4Vector,@function 1519 .align 4 1520_Level4Vector: 1521 wsr a0, EXCSAVE_4 /* preserve a0 */ 1522 call0 _xt_highint4 /* load interrupt handler */ 1523 /* never returns here - call0 is used as a jump (see note at top) */ 1524 1525 .end literal_prefix 1526 1527 .text 1528 .type _xt_highint4,@function 1529 .align 4 1530_xt_highint4: 1531 1532 #ifdef XT_INTEXC_HOOKS 1533 /* Call interrupt hook if present to (pre)handle interrupts. */ 1534 movi a0, _xt_intexc_hooks 1535 l32i a0, a0, 4<<2 1536 beqz a0, 1f 1537.Ln_xt_highint4_call_hook: 1538 callx0 a0 /* must NOT disturb stack! */ 15391: 1540 #endif 1541 1542 /* USER_EDIT: 1543 ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE. 1544 */ 1545 1546 .align 4 1547.L_xt_highint4_exit: 1548 rsr a0, EXCSAVE_4 /* restore a0 */ 1549 rfi 4 1550 1551#endif /* Level 4 */ 1552 1553#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5 1554 1555 .begin literal_prefix .Level5InterruptVector 1556 .section .Level5InterruptVector.text, "ax" 1557 .global _Level5Vector 1558 .type _Level5Vector,@function 1559 .align 4 1560_Level5Vector: 1561 wsr a0, EXCSAVE_5 /* preserve a0 */ 1562 call0 _xt_highint5 /* load interrupt handler */ 1563 /* never returns here - call0 is used as a jump (see note at top) */ 1564 1565 .end literal_prefix 1566 1567 .text 1568 .type _xt_highint5,@function 1569 .align 4 1570_xt_highint5: 1571 1572 #ifdef XT_INTEXC_HOOKS 1573 /* Call interrupt hook if present to (pre)handle interrupts. */ 1574 movi a0, _xt_intexc_hooks 1575 l32i a0, a0, 5<<2 1576 beqz a0, 1f 1577.Ln_xt_highint5_call_hook: 1578 callx0 a0 /* must NOT disturb stack! */ 15791: 1580 #endif 1581 1582 /* USER_EDIT: 1583 ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE. 1584 */ 1585 1586 .align 4 1587.L_xt_highint5_exit: 1588 rsr a0, EXCSAVE_5 /* restore a0 */ 1589 rfi 5 1590 1591#endif /* Level 5 */ 1592 1593#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6 1594 1595 .begin literal_prefix .Level6InterruptVector 1596 .section .Level6InterruptVector.text, "ax" 1597 .global _Level6Vector 1598 .type _Level6Vector,@function 1599 .align 4 1600_Level6Vector: 1601 wsr a0, EXCSAVE_6 /* preserve a0 */ 1602 call0 _xt_highint6 /* load interrupt handler */ 1603 /* never returns here - call0 is used as a jump (see note at top) */ 1604 1605 .end literal_prefix 1606 1607 .text 1608 .type _xt_highint6,@function 1609 .align 4 1610_xt_highint6: 1611 1612 #ifdef XT_INTEXC_HOOKS 1613 /* Call interrupt hook if present to (pre)handle interrupts. */ 1614 movi a0, _xt_intexc_hooks 1615 l32i a0, a0, 6<<2 1616 beqz a0, 1f 1617.Ln_xt_highint6_call_hook: 1618 callx0 a0 /* must NOT disturb stack! */ 16191: 1620 #endif 1621 1622 /* USER_EDIT: 1623 ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE. 1624 */ 1625 1626 .align 4 1627.L_xt_highint6_exit: 1628 rsr a0, EXCSAVE_6 /* restore a0 */ 1629 rfi 6 1630 1631#endif /* Level 6 */ 1632 1633#if XCHAL_HAVE_NMI 1634 1635 .begin literal_prefix .NMIExceptionVector 1636 .section .NMIExceptionVector.text, "ax" 1637 .global _NMIExceptionVector 1638 .type _NMIExceptionVector,@function 1639 .align 4 1640_NMIExceptionVector: 1641 wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */ 1642 call0 _xt_nmi /* load interrupt handler */ 1643 /* never returns here - call0 is used as a jump (see note at top) */ 1644 1645 .end literal_prefix 1646 1647 .text 1648 .type _xt_nmi,@function 1649 .align 4 1650_xt_nmi: 1651 1652 #ifdef XT_INTEXC_HOOKS 1653 /* Call interrupt hook if present to (pre)handle interrupts. */ 1654 movi a0, _xt_intexc_hooks 1655 l32i a0, a0, XCHAL_NMILEVEL<<2 1656 beqz a0, 1f 1657.Ln_xt_nmi_call_hook: 1658 callx0 a0 /* must NOT disturb stack! */ 16591: 1660 #endif 1661 1662 /* USER_EDIT: 1663 ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE. 1664 */ 1665 1666 .align 4 1667.L_xt_nmi_exit: 1668 rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */ 1669 rfi XCHAL_NMILEVEL 1670 1671#endif /* NMI */ 1672 1673 1674/******************************************************************************* 1675 1676WINDOW OVERFLOW AND UNDERFLOW EXCEPTION VECTORS AND ALLOCA EXCEPTION HANDLER 1677 1678Here is the code for each window overflow/underflow exception vector and 1679(interspersed) efficient code for handling the alloca exception cause. 1680Window exceptions are handled entirely in the vector area and are very 1681tight for performance. The alloca exception is also handled entirely in 1682the window vector area so comes at essentially no cost in code size. 1683Users should never need to modify them and Cadence Design Systems recommends 1684they do not. 1685 1686Window handlers go at predetermined vector locations according to the 1687Xtensa hardware configuration, which is ensured by their placement in a 1688special section known to the Xtensa linker support package (LSP). Since 1689their offsets in that section are always the same, the LSPs do not define 1690a section per vector. 1691 1692These things are coded for XEA2 only (XEA1 is not supported). 1693 1694Note on Underflow Handlers: 1695The underflow handler for returning from call[i+1] to call[i] 1696must preserve all the registers from call[i+1]'s window. 1697In particular, a0 and a1 must be preserved because the RETW instruction 1698will be reexecuted (and may even underflow if an intervening exception 1699has flushed call[i]'s registers). 1700Registers a2 and up may contain return values. 1701 1702*******************************************************************************/ 1703 1704#if XCHAL_HAVE_WINDOWED 1705 1706 .section .WindowVectors.text, "ax" 1707 1708/* 1709-------------------------------------------------------------------------------- 1710Window Overflow Exception for Call4. 1711 1712Invoked if a call[i] referenced a register (a4-a15) 1713that contains data from ancestor call[j]; 1714call[j] had done a call4 to call[j+1]. 1715On entry here: 1716 window rotated to call[j] start point; 1717 a0-a3 are registers to be saved; 1718 a4-a15 must be preserved; 1719 a5 is call[j+1]'s stack pointer. 1720-------------------------------------------------------------------------------- 1721*/ 1722 1723 .org 0x0 1724 .global _WindowOverflow4 1725_WindowOverflow4: 1726 1727 s32e a0, a5, -16 /* save a0 to call[j+1]'s stack frame */ 1728 s32e a1, a5, -12 /* save a1 to call[j+1]'s stack frame */ 1729 s32e a2, a5, -8 /* save a2 to call[j+1]'s stack frame */ 1730 s32e a3, a5, -4 /* save a3 to call[j+1]'s stack frame */ 1731 rfwo /* rotates back to call[i] position */ 1732 1733/* 1734-------------------------------------------------------------------------------- 1735Window Underflow Exception for Call4 1736 1737Invoked by RETW returning from call[i+1] to call[i] 1738where call[i]'s registers must be reloaded (not live in ARs); 1739where call[i] had done a call4 to call[i+1]. 1740On entry here: 1741 window rotated to call[i] start point; 1742 a0-a3 are undefined, must be reloaded with call[i].reg[0..3]; 1743 a4-a15 must be preserved (they are call[i+1].reg[0..11]); 1744 a5 is call[i+1]'s stack pointer. 1745-------------------------------------------------------------------------------- 1746*/ 1747 1748 .org 0x40 1749 .global _WindowUnderflow4 1750_WindowUnderflow4: 1751 1752 l32e a0, a5, -16 /* restore a0 from call[i+1]'s stack frame */ 1753 l32e a1, a5, -12 /* restore a1 from call[i+1]'s stack frame */ 1754 l32e a2, a5, -8 /* restore a2 from call[i+1]'s stack frame */ 1755 l32e a3, a5, -4 /* restore a3 from call[i+1]'s stack frame */ 1756 rfwu 1757 1758/* 1759-------------------------------------------------------------------------------- 1760Handle alloca exception generated by interruptee executing 'movsp'. 1761This uses space between the window vectors, so is essentially "free". 1762All interruptee's regs are intact except a0 which is saved in EXCSAVE_1, 1763and PS.EXCM has been set by the exception hardware (can't be interrupted). 1764The fact the alloca exception was taken means the registers associated with 1765the base-save area have been spilled and will be restored by the underflow 1766handler, so those 4 registers are available for scratch. 1767The code is optimized to avoid unaligned branches and minimize cache misses. 1768-------------------------------------------------------------------------------- 1769*/ 1770 1771 .align 4 1772 .global _xt_alloca_exc 1773_xt_alloca_exc: 1774 1775 rsr a0, WINDOWBASE /* grab WINDOWBASE before rotw changes it */ 1776 rotw -1 /* WINDOWBASE goes to a4, new a0-a3 are scratch */ 1777 rsr a2, PS 1778 extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS 1779 xor a3, a3, a4 /* bits changed from old to current windowbase */ 1780 rsr a4, EXCSAVE_1 /* restore original a0 (now in a4) */ 1781 slli a3, a3, XCHAL_PS_OWB_SHIFT 1782 xor a2, a2, a3 /* flip changed bits in old window base */ 1783 wsr a2, PS /* update PS.OWB to new window base */ 1784 rsync 1785 1786 _bbci.l a4, 31, _WindowUnderflow4 1787 rotw -1 /* original a0 goes to a8 */ 1788 _bbci.l a8, 30, _WindowUnderflow8 1789 rotw -1 1790 j _WindowUnderflow12 1791 1792/* 1793-------------------------------------------------------------------------------- 1794Window Overflow Exception for Call8 1795 1796Invoked if a call[i] referenced a register (a4-a15) 1797that contains data from ancestor call[j]; 1798call[j] had done a call8 to call[j+1]. 1799On entry here: 1800 window rotated to call[j] start point; 1801 a0-a7 are registers to be saved; 1802 a8-a15 must be preserved; 1803 a9 is call[j+1]'s stack pointer. 1804-------------------------------------------------------------------------------- 1805*/ 1806 1807 .org 0x80 1808 .global _WindowOverflow8 1809_WindowOverflow8: 1810 1811 s32e a0, a9, -16 /* save a0 to call[j+1]'s stack frame */ 1812 l32e a0, a1, -12 /* a0 <- call[j-1]'s sp 1813 (used to find end of call[j]'s frame) */ 1814 s32e a1, a9, -12 /* save a1 to call[j+1]'s stack frame */ 1815 s32e a2, a9, -8 /* save a2 to call[j+1]'s stack frame */ 1816 s32e a3, a9, -4 /* save a3 to call[j+1]'s stack frame */ 1817 s32e a4, a0, -32 /* save a4 to call[j]'s stack frame */ 1818 s32e a5, a0, -28 /* save a5 to call[j]'s stack frame */ 1819 s32e a6, a0, -24 /* save a6 to call[j]'s stack frame */ 1820 s32e a7, a0, -20 /* save a7 to call[j]'s stack frame */ 1821 rfwo /* rotates back to call[i] position */ 1822 1823/* 1824-------------------------------------------------------------------------------- 1825Window Underflow Exception for Call8 1826 1827Invoked by RETW returning from call[i+1] to call[i] 1828where call[i]'s registers must be reloaded (not live in ARs); 1829where call[i] had done a call8 to call[i+1]. 1830On entry here: 1831 window rotated to call[i] start point; 1832 a0-a7 are undefined, must be reloaded with call[i].reg[0..7]; 1833 a8-a15 must be preserved (they are call[i+1].reg[0..7]); 1834 a9 is call[i+1]'s stack pointer. 1835-------------------------------------------------------------------------------- 1836*/ 1837 1838 .org 0xC0 1839 .global _WindowUnderflow8 1840_WindowUnderflow8: 1841 1842 l32e a0, a9, -16 /* restore a0 from call[i+1]'s stack frame */ 1843 l32e a1, a9, -12 /* restore a1 from call[i+1]'s stack frame */ 1844 l32e a2, a9, -8 /* restore a2 from call[i+1]'s stack frame */ 1845 l32e a7, a1, -12 /* a7 <- call[i-1]'s sp 1846 (used to find end of call[i]'s frame) */ 1847 l32e a3, a9, -4 /* restore a3 from call[i+1]'s stack frame */ 1848 l32e a4, a7, -32 /* restore a4 from call[i]'s stack frame */ 1849 l32e a5, a7, -28 /* restore a5 from call[i]'s stack frame */ 1850 l32e a6, a7, -24 /* restore a6 from call[i]'s stack frame */ 1851 l32e a7, a7, -20 /* restore a7 from call[i]'s stack frame */ 1852 rfwu 1853 1854/* 1855-------------------------------------------------------------------------------- 1856Window Overflow Exception for Call12 1857 1858Invoked if a call[i] referenced a register (a4-a15) 1859that contains data from ancestor call[j]; 1860call[j] had done a call12 to call[j+1]. 1861On entry here: 1862 window rotated to call[j] start point; 1863 a0-a11 are registers to be saved; 1864 a12-a15 must be preserved; 1865 a13 is call[j+1]'s stack pointer. 1866-------------------------------------------------------------------------------- 1867*/ 1868 1869 .org 0x100 1870 .global _WindowOverflow12 1871_WindowOverflow12: 1872 1873 s32e a0, a13, -16 /* save a0 to call[j+1]'s stack frame */ 1874 l32e a0, a1, -12 /* a0 <- call[j-1]'s sp 1875 (used to find end of call[j]'s frame) */ 1876 s32e a1, a13, -12 /* save a1 to call[j+1]'s stack frame */ 1877 s32e a2, a13, -8 /* save a2 to call[j+1]'s stack frame */ 1878 s32e a3, a13, -4 /* save a3 to call[j+1]'s stack frame */ 1879 s32e a4, a0, -48 /* save a4 to end of call[j]'s stack frame */ 1880 s32e a5, a0, -44 /* save a5 to end of call[j]'s stack frame */ 1881 s32e a6, a0, -40 /* save a6 to end of call[j]'s stack frame */ 1882 s32e a7, a0, -36 /* save a7 to end of call[j]'s stack frame */ 1883 s32e a8, a0, -32 /* save a8 to end of call[j]'s stack frame */ 1884 s32e a9, a0, -28 /* save a9 to end of call[j]'s stack frame */ 1885 s32e a10, a0, -24 /* save a10 to end of call[j]'s stack frame */ 1886 s32e a11, a0, -20 /* save a11 to end of call[j]'s stack frame */ 1887 rfwo /* rotates back to call[i] position */ 1888 1889/* 1890-------------------------------------------------------------------------------- 1891Window Underflow Exception for Call12 1892 1893Invoked by RETW returning from call[i+1] to call[i] 1894where call[i]'s registers must be reloaded (not live in ARs); 1895where call[i] had done a call12 to call[i+1]. 1896On entry here: 1897 window rotated to call[i] start point; 1898 a0-a11 are undefined, must be reloaded with call[i].reg[0..11]; 1899 a12-a15 must be preserved (they are call[i+1].reg[0..3]); 1900 a13 is call[i+1]'s stack pointer. 1901-------------------------------------------------------------------------------- 1902*/ 1903 1904 .org 0x140 1905 .global _WindowUnderflow12 1906_WindowUnderflow12: 1907 1908 l32e a0, a13, -16 /* restore a0 from call[i+1]'s stack frame */ 1909 l32e a1, a13, -12 /* restore a1 from call[i+1]'s stack frame */ 1910 l32e a2, a13, -8 /* restore a2 from call[i+1]'s stack frame */ 1911 l32e a11, a1, -12 /* a11 <- call[i-1]'s sp 1912 (used to find end of call[i]'s frame) */ 1913 l32e a3, a13, -4 /* restore a3 from call[i+1]'s stack frame */ 1914 l32e a4, a11, -48 /* restore a4 from end of call[i]'s stack frame */ 1915 l32e a5, a11, -44 /* restore a5 from end of call[i]'s stack frame */ 1916 l32e a6, a11, -40 /* restore a6 from end of call[i]'s stack frame */ 1917 l32e a7, a11, -36 /* restore a7 from end of call[i]'s stack frame */ 1918 l32e a8, a11, -32 /* restore a8 from end of call[i]'s stack frame */ 1919 l32e a9, a11, -28 /* restore a9 from end of call[i]'s stack frame */ 1920 l32e a10, a11, -24 /* restore a10 from end of call[i]'s stack frame */ 1921 l32e a11, a11, -20 /* restore a11 from end of call[i]'s stack frame */ 1922 rfwu 1923 1924#endif /* XCHAL_HAVE_WINDOWED */ 1925