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