| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226 |
- /*
- * SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc.
- *
- * SPDX-License-Identifier: MIT
- *
- * SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD
- */
- /*
- * Copyright (c) 2015-2019 Cadence Design Systems, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- /*
- XTENSA VECTORS AND LOW LEVEL HANDLERS FOR AN RTOS
- Xtensa low level exception and interrupt vectors and handlers for an RTOS.
- Interrupt handlers and user exception handlers support interaction with
- the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT before and
- after user's specific interrupt handlers. These macros are defined in
- xtensa_<rtos>.h to call suitable functions in a specific RTOS.
- Users can install application-specific interrupt handlers for low and
- medium level interrupts, by calling xt_set_interrupt_handler(). These
- handlers can be written in C, and must obey C calling convention. The
- handler table is indexed by the interrupt number. Each handler may be
- provided with an argument.
- Note that the system timer interrupt is handled specially, and is
- dispatched to the RTOS-specific handler. This timer cannot be hooked
- by application code.
- Optional hooks are also provided to install a handler per level at
- run-time, made available by compiling this source file with
- '-DXT_INTEXC_HOOKS' (useful for automated testing).
- !! This file is a template that usually needs to be modified to handle !!
- !! application specific interrupts. Search USER_EDIT for helpful comments !!
- !! on where to insert handlers and how to write them. !!
- Users can also install application-specific exception handlers in the
- same way, by calling xt_set_exception_handler(). One handler slot is
- provided for each exception type. Note that some exceptions are handled
- by the porting layer itself, and cannot be taken over by application
- code in this manner. These are the alloca, syscall, and coprocessor
- exceptions.
- The exception handlers can be written in C, and must follow C calling
- convention. Each handler is passed a pointer to an exception frame as
- its single argument. The exception frame is created on the stack, and
- holds the saved context of the thread that took the exception. If the
- handler returns, the context will be restored and the instruction that
- caused the exception will be retried. If the handler makes any changes
- to the saved state in the exception frame, the changes will be applied
- when restoring the context.
- Because Xtensa is a configurable architecture, this port supports all user
- generated configurations (except restrictions stated in the release notes).
- This is accomplished by conditional compilation using macros and functions
- defined in the Xtensa HAL (hardware adaptation layer) for your configuration.
- Only the relevant parts of this file will be included in your RTOS build.
- For example, this file provides interrupt vector templates for all types and
- all priority levels, but only the ones in your configuration are built.
- NOTES on the use of 'call0' for long jumps instead of 'j':
- 1. This file should be assembled with the -mlongcalls option to xt-xcc.
- 2. The -mlongcalls compiler option causes 'call0 dest' to be expanded to
- a sequence 'l32r a0, dest' 'callx0 a0' which works regardless of the
- distance from the call to the destination. The linker then relaxes
- it back to 'call0 dest' if it determines that dest is within range.
- This allows more flexibility in locating code without the performance
- overhead of the 'l32r' literal data load in cases where the destination
- is in range of 'call0'. There is an additional benefit in that 'call0'
- has a longer range than 'j' due to the target being word-aligned, so
- the 'l32r' sequence is less likely needed.
- 3. The use of 'call0' with -mlongcalls requires that register a0 not be
- live at the time of the call, which is always the case for a function
- call but needs to be ensured if 'call0' is used as a jump in lieu of 'j'.
- 4. This use of 'call0' is independent of the C function call ABI.
- */
- #include "xtensa_rtos.h"
- #include "esp_private/panic_reason.h"
- #include "sdkconfig.h"
- #include "soc/soc.h"
- #include "xt_asm_utils.h"
- /*
- --------------------------------------------------------------------------------
- In order for backtracing to be able to trace from the pre-exception stack
- across to the exception stack (including nested interrupts), we need to create
- a pseudo base-save area to make it appear like the exception dispatcher was
- triggered by a CALL4 from the pre-exception code. In reality, the exception
- dispatcher uses the same window as pre-exception code, and only CALL0s are
- used within the exception dispatcher.
- To create the pseudo base-save area, we need to store a copy of the pre-exception's
- base save area (a0 to a4) below the exception dispatcher's SP. EXCSAVE_x will
- be used to store a copy of the SP that points to the interrupted code's exception
- frame just in case the exception dispatcher's SP does not point to the exception
- frame (which is the case when switching from task to interrupt stack).
- Clearing the pseudo base-save area is uncessary as the interrupt dispatcher
- will restore the current SP to that of the pre-exception SP.
- --------------------------------------------------------------------------------
- */
- #ifdef CONFIG_FREERTOS_INTERRUPT_BACKTRACE
- #define XT_DEBUG_BACKTRACE 1
- #endif
- /*
- --------------------------------------------------------------------------------
- Defines used to access _xtos_interrupt_table.
- --------------------------------------------------------------------------------
- */
- #define XIE_HANDLER 0
- #define XIE_ARG 4
- #define XIE_SIZE 8
- /*
- Macro get_percpu_entry_for - convert a per-core ID into a multicore entry.
- Basically does reg=reg*portNUM_PROCESSORS+current_core_id
- Multiple versions here to optimize for specific portNUM_PROCESSORS values.
- */
- .macro get_percpu_entry_for reg scratch
- #if (portNUM_PROCESSORS == 1)
- /* No need to do anything */
- #elif (portNUM_PROCESSORS == 2)
- /* Optimized 2-core code. */
- getcoreid \scratch
- addx2 \reg,\reg,\scratch
- #else
- /* Generalized n-core code. Untested! */
- movi \scratch,portNUM_PROCESSORS
- mull \scratch,\reg,\scratch
- getcoreid \reg
- add \reg,\scratch,\reg
- #endif
- .endm
- /*
- --------------------------------------------------------------------------------
- Macro extract_msb - return the input with only the highest bit set.
- Input : "ain" - Input value, clobbered.
- Output : "aout" - Output value, has only one bit set, MSB of "ain".
- The two arguments must be different AR registers.
- --------------------------------------------------------------------------------
- */
- .macro extract_msb aout ain
- 1:
- addi \aout, \ain, -1 /* aout = ain - 1 */
- and \ain, \ain, \aout /* ain = ain & aout */
- bnez \ain, 1b /* repeat until ain == 0 */
- addi \aout, \aout, 1 /* return aout + 1 */
- .endm
- /*
- --------------------------------------------------------------------------------
- Macro dispatch_c_isr - dispatch interrupts to user ISRs.
- This will dispatch to user handlers (if any) that are registered in the
- XTOS dispatch table (_xtos_interrupt_table). These handlers would have
- been registered by calling _xtos_set_interrupt_handler(). There is one
- exception - the timer interrupt used by the OS will not be dispatched
- to a user handler - this must be handled by the caller of this macro.
- Level triggered and software interrupts are automatically deasserted by
- this code.
- ASSUMPTIONS:
- -- PS.INTLEVEL is set to "level" at entry
- -- PS.EXCM = 0, C calling enabled
- NOTE: For CALL0 ABI, a12-a15 have not yet been saved.
- NOTE: This macro will use registers a0 and a2-a6. The arguments are:
- level -- interrupt level
- mask -- interrupt bitmask for this level
- --------------------------------------------------------------------------------
- */
- .macro dispatch_c_isr level mask
- #ifdef CONFIG_PM_TRACE
- movi a6, 0 /* = ESP_PM_TRACE_IDLE */
- getcoreid a7
- call4 esp_pm_trace_exit
- #endif // CONFIG_PM_TRACE
- /* Get mask of pending, enabled interrupts at this level into a2. */
- .L_xt_user_int_\level :
- rsr a2, INTENABLE
- rsr a3, INTERRUPT
- movi a4, \mask
- and a2, a2, a3
- and a2, a2, a4
- beqz a2, 9f /* nothing to do */
- /* This bit of code provides a nice debug backtrace in the debugger.
- It does take a few more instructions, so undef XT_DEBUG_BACKTRACE
- if you want to save the cycles.
- At this point, the exception frame should have been allocated and filled,
- and current sp points to the interrupt stack (for non-nested interrupt)
- or below the allocated exception frame (for nested interrupts). Copy the
- pre-exception's base save area below the current SP.
- */
- #ifdef XT_DEBUG_BACKTRACE
- #ifndef __XTENSA_CALL0_ABI__
- rsr a0, EXCSAVE_1 + \level - 1 /* Get exception frame pointer stored in EXCSAVE_x */
- l32i a3, a0, XT_STK_A0 /* Copy pre-exception a0 (return address) */
- s32e a3, a1, -16
- l32i a3, a0, XT_STK_A1 /* Copy pre-exception a1 (stack pointer) */
- s32e a3, a1, -12
- /* Backtracing only needs a0 and a1, no need to create full base save area.
- Also need to change current frame's return address to point to pre-exception's
- last run instruction.
- */
- rsr a0, EPC_1 + \level - 1 /* return address */
- movi a4, 0xC0000000 /* constant with top 2 bits set (call size) */
- or a0, a0, a4 /* set top 2 bits */
- addx2 a0, a4, a0 /* clear top bit -- simulating call4 size */
- #endif
- #endif
- #ifdef CONFIG_PM_ENABLE
- call4 esp_pm_impl_isr_hook
- #endif
- #ifdef XT_INTEXC_HOOKS
- /* Call interrupt hook if present to (pre)handle interrupts. */
- movi a4, _xt_intexc_hooks
- l32i a4, a4, \level << 2
- beqz a4, 2f
- #ifdef __XTENSA_CALL0_ABI__
- callx0 a4
- beqz a2, 9f
- #else
- mov a6, a2
- callx4 a4
- beqz a6, 9f
- mov a2, a6
- #endif
- 2:
- #endif
- /* Now look up in the dispatch table and call user ISR if any. */
- /* If multiple bits are set then MSB has highest priority. */
- extract_msb a4, a2 /* a4 = MSB of a2, a2 trashed */
- #ifdef XT_USE_SWPRI
- /* Enable all interrupts at this level that are numerically higher
- than the one we just selected, since they are treated as higher
- priority.
- */
- movi a3, \mask /* a3 = all interrupts at this level */
- add a2, a4, a4 /* a2 = a4 << 1 */
- addi a2, a2, -1 /* a2 = mask of 1's <= a4 bit */
- and a2, a2, a3 /* a2 = mask of all bits <= a4 at this level */
- movi a3, _xt_intdata
- l32i a6, a3, 4 /* a6 = _xt_vpri_mask */
- neg a2, a2
- addi a2, a2, -1 /* a2 = mask to apply */
- and a5, a6, a2 /* mask off all bits <= a4 bit */
- s32i a5, a3, 4 /* update _xt_vpri_mask */
- rsr a3, INTENABLE
- and a3, a3, a2 /* mask off all bits <= a4 bit */
- wsr a3, INTENABLE
- rsil a3, \level - 1 /* lower interrupt level by 1 */
- #endif
- #ifdef XT_RTOS_TIMER_INT
- movi a3, XT_TIMER_INTEN /* a3 = timer interrupt bit */
- wsr a4, INTCLEAR /* clear sw or edge-triggered interrupt */
- beq a3, a4, 7f /* if timer interrupt then skip table */
- #else
- wsr a4, INTCLEAR /* clear sw or edge-triggered interrupt */
- #endif // XT_RTOS_TIMER_INT
- find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */
- get_percpu_entry_for a3, a12
- movi a4, _xt_interrupt_table
- addx8 a3, a3, a4 /* a3 = address of interrupt table entry */
- l32i a4, a3, XIE_HANDLER /* a4 = handler address */
- #ifdef __XTENSA_CALL0_ABI__
- mov a12, a6 /* save in callee-saved reg */
- l32i a2, a3, XIE_ARG /* a2 = handler arg */
- callx0 a4 /* call handler */
- mov a2, a12
- #else
- mov a2, a6 /* save in windowed reg */
- l32i a6, a3, XIE_ARG /* a6 = handler arg */
- callx4 a4 /* call handler */
- #endif
- #ifdef XT_USE_SWPRI
- j 8f
- #else
- j .L_xt_user_int_\level /* check for more interrupts */
- #endif
- #ifdef XT_RTOS_TIMER_INT
- 7:
- .ifeq XT_TIMER_INTPRI - \level
- .L_xt_user_int_timer_\level :
- /*
- Interrupt handler for the RTOS tick timer if at this level.
- We'll be reading the interrupt state again after this call
- so no need to preserve any registers except a6 (vpri_mask).
- */
- #ifdef __XTENSA_CALL0_ABI__
- mov a12, a6
- call0 XT_RTOS_TIMER_INT
- mov a2, a12
- #else
- mov a2, a6
- call4 XT_RTOS_TIMER_INT
- #endif
- .endif
- #endif // XT_RTOS_TIMER_INT
- #ifdef XT_USE_SWPRI
- j 8f
- #else
- j .L_xt_user_int_\level /* check for more interrupts */
- #endif
- #ifdef XT_USE_SWPRI
- 8:
- /* Restore old value of _xt_vpri_mask from a2. Also update INTENABLE from
- virtual _xt_intenable which _could_ have changed during interrupt
- processing. */
- movi a3, _xt_intdata
- l32i a4, a3, 0 /* a4 = _xt_intenable */
- s32i a2, a3, 4 /* update _xt_vpri_mask */
- and a4, a4, a2 /* a4 = masked intenable */
- wsr a4, INTENABLE /* update INTENABLE */
- #endif
- 9:
- /* done */
- .endm
- .section .rodata, "a"
- .align 4
- /*
- --------------------------------------------------------------------------------
- Hooks to dynamically install handlers for exceptions and interrupts.
- Allows automated regression frameworks to install handlers per test.
- Consists of an array of function pointers indexed by interrupt level,
- with index 0 containing the entry for user exceptions.
- Initialized with all 0s, meaning no handler is installed at each level.
- See comment in xtensa_rtos.h for more details.
- *WARNING* This array is for all CPUs, that is, installing a hook for
- one CPU will install it for all others as well!
- --------------------------------------------------------------------------------
- */
- #ifdef XT_INTEXC_HOOKS
- .data
- .global _xt_intexc_hooks
- .type _xt_intexc_hooks,@object
- .align 4
- _xt_intexc_hooks:
- .fill XT_INTEXC_HOOK_NUM, 4, 0
- #endif
- /*
- --------------------------------------------------------------------------------
- EXCEPTION AND LEVEL 1 INTERRUPT VECTORS AND LOW LEVEL HANDLERS
- (except window exception vectors).
- Each vector goes at a predetermined location according to the Xtensa
- hardware configuration, which is ensured by its placement in a special
- section known to the Xtensa linker support package (LSP). It performs
- the minimum necessary before jumping to the handler in the .text section.
- The corresponding handler goes in the normal .text section. It sets up
- the appropriate stack frame, saves a few vector-specific registers and
- calls XT_RTOS_INT_ENTER to save the rest of the interrupted context
- and enter the RTOS, then sets up a C environment. It then calls the
- user's interrupt handler code (which may be coded in C) and finally
- calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling.
- While XT_RTOS_INT_EXIT does not return directly to the interruptee,
- eventually the RTOS scheduler will want to dispatch the interrupted
- task or handler. The scheduler will return to the exit point that was
- saved in the interrupt stack frame at XT_STK_EXIT.
- --------------------------------------------------------------------------------
- */
- /*
- --------------------------------------------------------------------------------
- Debug Exception.
- --------------------------------------------------------------------------------
- */
- #if XCHAL_HAVE_DEBUG
- .begin literal_prefix .DebugExceptionVector
- .section .DebugExceptionVector.text, "ax"
- .global _DebugExceptionVector
- .align 4
- .global xt_debugexception
- _DebugExceptionVector:
- wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* preserve a0 */
- J xt_debugexception /* load exception handler */
- .end literal_prefix
- .global xt_debugexception
- .weak xt_debugexception
- .set xt_debugexception, _xt_debugexception
- .section .iram1,"ax"
- .type _xt_debugexception,@function
- .align 4
- _xt_debugexception:
- #if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
- s32i a0, sp, XT_STK_EXIT
- #define XT_DEBUGCAUSE_DI (5)
- getcoreid a0
- #if (CONFIG_BTDM_CTRL_PINNED_TO_CORE == PRO_CPU_NUM)
- beqz a0, 1f
- #else
- bnez a0, 1f
- #endif
- rsr a0, DEBUGCAUSE
- extui a0, a0, XT_DEBUGCAUSE_DI, 1
- bnez a0, _xt_debug_di_exc
- 1:
- #endif //(CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
- movi a0,PANIC_RSN_DEBUGEXCEPTION
- wsr a0,EXCCAUSE
- /* _xt_panic assumes a level 1 exception. As we're
- crashing anyhow, copy EPC & EXCSAVE from DEBUGLEVEL
- to level 1. */
- rsr a0,(EPC + XCHAL_DEBUGLEVEL)
- wsr a0,EPC_1
- rsr a0,(EXCSAVE + XCHAL_DEBUGLEVEL)
- wsr a0,EXCSAVE_1
- #if CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
- J _xt_panic_gdbstub /* For gdbstub we make jump */
- #else
- call0 _xt_panic /* does not return */
- #endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
- rfi XCHAL_DEBUGLEVEL
- #if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
- .align 4
- _xt_debug_di_exc:
- /*
- The delay time can be calculated by the following formula:
- T = ceil(0.25 + max(t1, t2)) us
- t1 = 80 / f1, t2 = (1 + 14/N) * 20 / f2
- f1: PSRAM access frequency, unit: MHz.
- f2: Flash access frequency, unit: MHz.
- When flash is slow/fast read, N = 1.
- When flash is DOUT/DIO read, N = 2.
- When flash is QOUT/QIO read, N = 4.
- And after testing, when CPU frequency is 240 MHz, it will take 1us to loop 27 times.
- */
- #if defined(CONFIG_ESPTOOLPY_FLASHMODE_QIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_QOUT)
- # if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M)
- movi a0, 54
- # elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M)
- movi a0, 81
- # elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M)
- movi a0, 81
- # elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M)
- movi a0, 108
- # else
- movi a0, 135
- # endif
- #elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_DOUT)
- # if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M)
- movi a0, 81
- # elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M)
- movi a0, 81
- # elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M)
- movi a0, 135
- # elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M)
- movi a0, 189
- # else
- movi a0, 243
- # endif
- #else
- movi a0, 243
- #endif
- 1: addi a0, a0, -1 /* delay_us(N) */
- .rept 4
- nop
- .endr
- bnez a0, 1b
- rsr a0, EXCSAVE+XCHAL_DEBUGLEVEL
- rfi XCHAL_DEBUGLEVEL
- #endif //(CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
- #endif // XCHAL_HAVE_DEBUG
- /*
- --------------------------------------------------------------------------------
- Double Exception.
- Double exceptions are not a normal occurrence. They indicate a bug of some kind.
- --------------------------------------------------------------------------------
- */
- #ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR
- .begin literal_prefix .DoubleExceptionVector
- .section .DoubleExceptionVector.text, "ax"
- .global _DoubleExceptionVector
- .align 4
- _DoubleExceptionVector:
- #if XCHAL_HAVE_DEBUG
- break 1, 4 /* unhandled double exception */
- #endif
- movi a0,PANIC_RSN_DOUBLEEXCEPTION
- wsr a0,EXCCAUSE
- call0 _xt_panic /* does not return */
- rfde /* make a0 point here not later */
- .end literal_prefix
- #endif /* XCHAL_DOUBLEEXC_VECTOR_VADDR */
- /*
- --------------------------------------------------------------------------------
- Kernel Exception (including Level 1 Interrupt from kernel mode).
- --------------------------------------------------------------------------------
- */
- .begin literal_prefix .KernelExceptionVector
- .section .KernelExceptionVector.text, "ax"
- .global _KernelExceptionVector
- .align 4
- _KernelExceptionVector:
- wsr a0, EXCSAVE_1 /* preserve a0 */
- call0 _xt_kernel_exc /* kernel exception handler */
- /* never returns here - call0 is used as a jump (see note at top) */
- .end literal_prefix
- .section .iram1,"ax"
- .align 4
- _xt_kernel_exc:
- #if XCHAL_HAVE_DEBUG
- break 1, 0 /* unhandled kernel exception */
- #endif
- movi a0,PANIC_RSN_KERNELEXCEPTION
- wsr a0,EXCCAUSE
- call0 _xt_panic /* does not return */
- rfe /* make a0 point here not there */
- /*
- --------------------------------------------------------------------------------
- User Exception (including Level 1 Interrupt from user mode).
- --------------------------------------------------------------------------------
- */
- .begin literal_prefix .UserExceptionVector
- .section .UserExceptionVector.text, "ax"
- .global _UserExceptionVector
- .type _UserExceptionVector,@function
- .align 4
- _UserExceptionVector:
- wsr a0, EXCSAVE_1 /* preserve a0 */
- call0 _xt_user_exc /* user exception handler */
- /* never returns here - call0 is used as a jump (see note at top) */
- .end literal_prefix
- /*
- --------------------------------------------------------------------------------
- Insert some waypoints for jumping beyond the signed 8-bit range of
- conditional branch instructions, so the conditional branchces to specific
- exception handlers are not taken in the mainline. Saves some cycles in the
- mainline.
- --------------------------------------------------------------------------------
- */
- #ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
- .global LoadStoreErrorHandler
- .global AlignmentErrorHandler
- #endif
- .section .iram1,"ax"
- #if XCHAL_HAVE_WINDOWED
- .align 4
- _xt_to_alloca_exc:
- call0 _xt_alloca_exc /* in window vectors section */
- /* never returns here - call0 is used as a jump (see note at top) */
- #endif
- .align 4
- _xt_to_syscall_exc:
- call0 _xt_syscall_exc
- /* never returns here - call0 is used as a jump (see note at top) */
- #if XCHAL_CP_NUM > 0
- .align 4
- _xt_to_coproc_exc:
- call0 _xt_coproc_exc
- /* never returns here - call0 is used as a jump (see note at top) */
- #endif
- #ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
- .align 4
- _call_loadstore_handler:
- call0 LoadStoreErrorHandler
- /* This will return only if wrong opcode or address out of range*/
- j .LS_exit
- .align 4
- _call_alignment_handler:
- call0 AlignmentErrorHandler
- /* This will return only if wrong opcode or address out of range*/
- addi a0, a0, 1
- j .LS_exit
- #endif
- /*
- --------------------------------------------------------------------------------
- User exception handler.
- --------------------------------------------------------------------------------
- */
- .type _xt_user_exc,@function
- .align 4
- _xt_user_exc:
- /* If level 1 interrupt then jump to the dispatcher */
- rsr a0, EXCCAUSE
- bnei a0, EXCCAUSE_LEVEL1INTERRUPT, _xt_handle_exc
- j _xt_lowint1
- _xt_handle_exc:
- /* Handle any coprocessor exceptions. Rely on the fact that exception
- numbers above EXCCAUSE_CP0_DISABLED all relate to the coprocessors.
- */
- #if XCHAL_CP_NUM > 0
- bgeui a0, EXCCAUSE_CP0_DISABLED, _xt_to_coproc_exc
- #endif
- /* Handle alloca and syscall exceptions */
- #if XCHAL_HAVE_WINDOWED
- beqi a0, EXCCAUSE_ALLOCA, _xt_to_alloca_exc
- #endif
- beqi a0, EXCCAUSE_SYSCALL, _xt_to_syscall_exc
- #ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
- beqi a0, EXCCAUSE_LOAD_STORE_ERROR, _call_loadstore_handler
- addi a0, a0, -1
- beqi a0, 8, _call_alignment_handler
- addi a0, a0, 1
- .LS_exit:
- #endif
- /* Handle all other exceptions. All can have user-defined handlers. */
- /* NOTE: we'll stay on the user stack for exception handling. */
- /* Allocate exception frame and save minimal context. */
- mov a0, sp
- addi sp, sp, -XT_STK_FRMSZ
- s32i a0, sp, XT_STK_A1
- #if XCHAL_HAVE_WINDOWED
- s32e a0, sp, -12 /* for debug backtrace */
- #endif
- rsr a0, PS /* save interruptee's PS */
- s32i a0, sp, XT_STK_PS
- rsr a0, EPC_1 /* save interruptee's PC */
- s32i a0, sp, XT_STK_PC
- rsr a0, EXCSAVE_1 /* save interruptee's a0 */
- s32i a0, sp, XT_STK_A0
- #if XCHAL_HAVE_WINDOWED
- s32e a0, sp, -16 /* for debug backtrace */
- #endif
- s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */
- s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */
- call0 _xt_context_save
- /* Save exc cause and vaddr into exception frame */
- rsr a0, EXCCAUSE
- s32i a0, sp, XT_STK_EXCCAUSE
- rsr a0, EXCVADDR
- s32i a0, sp, XT_STK_EXCVADDR
- /* Set up PS for C, reenable debug and NMI interrupts, and clear EXCM. */
- #ifdef __XTENSA_CALL0_ABI__
- movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM
- #else
- movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM | PS_WOE
- #endif
- wsr a0, PS
- /*
- Create pseudo base save area. At this point, sp is still pointing to the
- allocated and filled exception stack frame.
- */
- #ifdef XT_DEBUG_BACKTRACE
- #ifndef __XTENSA_CALL0_ABI__
- l32i a3, sp, XT_STK_A0 /* Copy pre-exception a0 (return address) */
- s32e a3, sp, -16
- l32i a3, sp, XT_STK_A1 /* Copy pre-exception a1 (stack pointer) */
- s32e a3, sp, -12
- rsr a0, EPC_1 /* return address for debug backtrace */
- movi a5, 0xC0000000 /* constant with top 2 bits set (call size) */
- rsync /* wait for WSR.PS to complete */
- or a0, a0, a5 /* set top 2 bits */
- addx2 a0, a5, a0 /* clear top bit -- thus simulating call4 size */
- #else
- rsync /* wait for WSR.PS to complete */
- #endif
- #endif
- rsr a2, EXCCAUSE /* recover exc cause */
- #ifdef XT_INTEXC_HOOKS
- /*
- Call exception hook to pre-handle exceptions (if installed).
- Pass EXCCAUSE in a2, and check result in a2 (if -1, skip default handling).
- */
- movi a4, _xt_intexc_hooks
- l32i a4, a4, 0 /* user exception hook index 0 */
- beqz a4, 1f
- .Ln_xt_user_exc_call_hook:
- #ifdef __XTENSA_CALL0_ABI__
- callx0 a4
- beqi a2, -1, .L_xt_user_done
- #else
- mov a6, a2
- callx4 a4
- beqi a6, -1, .L_xt_user_done
- mov a2, a6
- #endif
- 1:
- #endif
- rsr a2, EXCCAUSE /* recover exc cause */
- movi a3, _xt_exception_table
- get_percpu_entry_for a2, a4
- addx4 a4, a2, a3 /* a4 = address of exception table entry */
- l32i a4, a4, 0 /* a4 = handler address */
- #ifdef __XTENSA_CALL0_ABI__
- mov a2, sp /* a2 = pointer to exc frame */
- callx0 a4 /* call handler */
- #else
- mov a6, sp /* a6 = pointer to exc frame */
- callx4 a4 /* call handler */
- #endif
- .L_xt_user_done:
- /* Restore context and return */
- call0 _xt_context_restore
- l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
- wsr a0, PS
- l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
- wsr a0, EPC_1
- l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
- l32i sp, sp, XT_STK_A1 /* remove exception frame */
- rsync /* ensure PS and EPC written */
- rfe /* PS.EXCM is cleared */
- /*
- --------------------------------------------------------------------------------
- Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
- on entry and used to return to a thread or interrupted interrupt handler.
- --------------------------------------------------------------------------------
- */
- .global _xt_user_exit
- .type _xt_user_exit,@function
- .align 4
- _xt_user_exit:
- l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
- wsr a0, PS
- l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
- wsr a0, EPC_1
- l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
- l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */
- rsync /* ensure PS and EPC written */
- rfe /* PS.EXCM is cleared */
- /*
- --------------------------------------------------------------------------------
- Syscall Exception Handler (jumped to from User Exception Handler).
- Syscall 0 is required to spill the register windows (no-op in Call 0 ABI).
- Only syscall 0 is handled here. Other syscalls return -1 to caller in a2.
- --------------------------------------------------------------------------------
- */
- .section .iram1,"ax"
- .type _xt_syscall_exc,@function
- .align 4
- _xt_syscall_exc:
- #ifdef __XTENSA_CALL0_ABI__
- /*
- Save minimal regs for scratch. Syscall 0 does nothing in Call0 ABI.
- Use a minimal stack frame (16B) to save A2 & A3 for scratch.
- PS.EXCM could be cleared here, but unlikely to improve worst-case latency.
- rsr a0, PS
- addi a0, a0, -PS_EXCM_MASK
- wsr a0, PS
- */
- addi sp, sp, -16
- s32i a2, sp, 8
- s32i a3, sp, 12
- #else /* Windowed ABI */
- /*
- Save necessary context and spill the register windows.
- PS.EXCM is still set and must remain set until after the spill.
- Reuse context save function though it saves more than necessary.
- For this reason, a full interrupt stack frame is allocated.
- */
- addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */
- s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */
- s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */
- call0 _xt_context_save
- #endif
- /*
- Grab the interruptee's PC and skip over the 'syscall' instruction.
- If it's at the end of a zero-overhead loop and it's not on the last
- iteration, decrement loop counter and skip to beginning of loop.
- */
- rsr a2, EPC_1 /* a2 = PC of 'syscall' */
- addi a3, a2, 3 /* ++PC */
- #if XCHAL_HAVE_LOOPS
- rsr a0, LEND /* if (PC == LEND */
- bne a3, a0, 1f
- rsr a0, LCOUNT /* && LCOUNT != 0) */
- beqz a0, 1f /* { */
- addi a0, a0, -1 /* --LCOUNT */
- rsr a3, LBEG /* PC = LBEG */
- wsr a0, LCOUNT /* } */
- #endif
- 1: wsr a3, EPC_1 /* update PC */
- /* Restore interruptee's context and return from exception. */
- #ifdef __XTENSA_CALL0_ABI__
- l32i a2, sp, 8
- l32i a3, sp, 12
- addi sp, sp, 16
- #else
- call0 _xt_context_restore
- addi sp, sp, XT_STK_FRMSZ
- #endif
- movi a0, -1
- movnez a2, a0, a2 /* return -1 if not syscall 0 */
- rsr a0, EXCSAVE_1
- rfe
- /*
- --------------------------------------------------------------------------------
- Co-Processor Exception Handler (jumped to from User Exception Handler).
- These exceptions are generated by co-processor instructions, which are only
- allowed in thread code (not in interrupts or kernel code). This restriction is
- deliberately imposed to reduce the burden of state-save/restore in interrupts.
- --------------------------------------------------------------------------------
- */
- #if XCHAL_CP_NUM > 0
- .section .rodata, "a"
- /* Offset to CP n save area in thread's CP save area. */
- .global _xt_coproc_sa_offset
- .type _xt_coproc_sa_offset,@object
- .align 16 /* minimize crossing cache boundaries */
- _xt_coproc_sa_offset:
- .word XT_CP0_SA, XT_CP1_SA, XT_CP2_SA, XT_CP3_SA
- .word XT_CP4_SA, XT_CP5_SA, XT_CP6_SA, XT_CP7_SA
- /* Bitmask for CP n's CPENABLE bit. */
- .type _xt_coproc_mask,@object
- .align 16,,8 /* try to keep it all in one cache line */
- .set i, 0
- _xt_coproc_mask:
- .rept XCHAL_CP_MAX
- .long (i<<16) | (1<<i) // upper 16-bits = i, lower = bitmask
- .set i, i+1
- .endr
- .data
- /* Owner thread of CP n, identified by thread's CP save area (0 = unowned). */
- .global _xt_coproc_owner_sa
- .type _xt_coproc_owner_sa,@object
- .align 16,,XCHAL_CP_MAX<<2 /* minimize crossing cache boundaries */
- _xt_coproc_owner_sa:
- .space (XCHAL_CP_MAX * portNUM_PROCESSORS) << 2
- /* Spinlock per core for accessing _xt_coproc_owner_sa array
- *
- * 0 = Spinlock available
- * PRID = Spinlock taken
- *
- * The lock provides mutual exclusion for accessing the _xt_coproc_owner_sa array.
- * The array can be modified by multiple cores simultaneously (via _xt_coproc_exc
- * and _xt_coproc_release). Therefore, this spinlock is defined to ensure thread
- * safe access of the _xt_coproc_owner_sa array.
- */
- #if portNUM_PROCESSORS > 1
- .global _xt_coproc_owner_sa_lock
- .type _xt_coproc_owner_sa_lock,@object
- .align 16 /* minimize crossing cache boundaries */
- _xt_coproc_owner_sa_lock:
- .space 4
- #endif /* portNUM_PROCESSORS > 1 */
- .section .iram1,"ax"
- .align 4
- .L_goto_invalid:
- j .L_xt_coproc_invalid /* not in a thread (invalid) */
- .align 4
- .L_goto_done:
- j .L_xt_coproc_done
- /*
- --------------------------------------------------------------------------------
- Coprocessor exception handler.
- At entry, only a0 has been saved (in EXCSAVE_1).
- --------------------------------------------------------------------------------
- */
- .type _xt_coproc_exc,@function
- .align 4
- _xt_coproc_exc:
- /* Allocate interrupt stack frame and save minimal context. */
- mov a0, sp /* sp == a1 */
- addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */
- s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */
- #if XCHAL_HAVE_WINDOWED
- s32e a0, sp, -12 /* for debug backtrace */
- #endif
- rsr a0, PS /* save interruptee's PS */
- s32i a0, sp, XT_STK_PS
- rsr a0, EPC_1 /* save interruptee's PC */
- s32i a0, sp, XT_STK_PC
- rsr a0, EXCSAVE_1 /* save interruptee's a0 */
- s32i a0, sp, XT_STK_A0
- #if XCHAL_HAVE_WINDOWED
- s32e a0, sp, -16 /* for debug backtrace */
- #endif
- movi a0, _xt_user_exit /* save exit point for dispatch */
- s32i a0, sp, XT_STK_EXIT
- rsr a0, EXCCAUSE
- s32i a5, sp, XT_STK_A5 /* save a5 */
- addi a5, a0, -EXCCAUSE_CP0_DISABLED /* a5 = CP index */
- /* Save a few more of interruptee's registers (a5 was already saved). */
- s32i a2, sp, XT_STK_A2
- s32i a3, sp, XT_STK_A3
- s32i a4, sp, XT_STK_A4
- #if portNUM_PROCESSORS > 1
- /* If multicore, we must save two more interruptee's register to use as
- * scratch when taking/releasing the _xt_coproc_owner_sa_lock spinlock. */
- s32i a6, sp, XT_STK_A6
- s32i a7, sp, XT_STK_A7
- #endif /* portNUM_PROCESSORS > 1 */
- s32i a15, sp, XT_STK_A15
- /* Call the RTOS coprocessor exception hook */
- call0 XT_RTOS_CP_EXC_HOOK
- /* Get co-processor state save area of new owner thread. */
- call0 XT_RTOS_CP_STATE /* a15 = new owner's save area */
- #if !CONFIG_FREERTOS_FPU_IN_ISR
- beqz a15, .L_goto_invalid /* not in a thread (invalid) */
- #endif
- /* Enable the co-processor's bit in CPENABLE. */
- movi a0, _xt_coproc_mask
- rsr a4, CPENABLE /* a4 = CPENABLE */
- addx4 a0, a5, a0 /* a0 = &_xt_coproc_mask[n] */
- l32i a0, a0, 0 /* a0 = (n << 16) | (1 << n) */
- extui a2, a0, 0, 16 /* coprocessor bitmask portion */
- or a4, a4, a2 /* a4 = CPENABLE | (1 << n) */
- wsr a4, CPENABLE
- /* Grab the xt_coproc_owner_sa owner array for current core */
- getcoreid a3 /* a3 = current core ID */
- movi a2, XCHAL_CP_MAX << 2 /* a2 = size of an owner array */
- mull a2, a2, a3 /* a2 = offset to the owner array of the current core*/
- movi a3, _xt_coproc_owner_sa /* a3 = base of all owner arrays */
- add a3, a3, a2 /* a3 = base of owner array of the current core */
- #if portNUM_PROCESSORS > 1
- /* If multicore, we must also acquire the _xt_coproc_owner_sa_lock spinlock
- * to ensure thread safe access of _xt_coproc_owner_sa between cores. */
- spinlock_take a6 a7 _xt_coproc_owner_sa_lock
- #endif /* portNUM_PROCESSORS > 1 */
- /* Get old coprocessor owner thread (save area ptr) and assign new one. */
- addx4 a3, a5, a3 /* a3 = &_xt_coproc_owner_sa[n] */
- l32i a2, a3, 0 /* a2 = old owner's save area */
- s32i a15, a3, 0 /* _xt_coproc_owner_sa[n] = new */
- rsync /* ensure wsr.CPENABLE is complete */
- #if portNUM_PROCESSORS > 1
- /* Release previously taken spinlock */
- spinlock_release a6 a7 _xt_coproc_owner_sa_lock
- #endif /* portNUM_PROCESSORS > 1 */
- /* Only need to context switch if new owner != old owner. */
- /* If float is necessary on ISR, we need to remove this check */
- /* below, because on restoring from ISR we may have new == old condition used
- * to force cp restore to next thread
- * Todo: IDF-6418
- */
- #if !CONFIG_FREERTOS_FPU_IN_ISR
- bne a15, a2, .L_switch_context
- j .L_goto_done /* new owner == old, we're done */
- .L_switch_context:
- #endif
- /* If no old owner then nothing to save. */
- beqz a2, .L_check_new
- /* If old owner not actively using CP then nothing to save. */
- l16ui a4, a2, XT_CPENABLE /* a4 = old owner's CPENABLE */
- bnone a4, a0, .L_check_new /* old owner not using CP */
- .L_save_old:
- /* Save old owner's coprocessor state. */
- movi a5, _xt_coproc_sa_offset
- /* Mark old owner state as no longer active (CPENABLE bit n clear). */
- xor a4, a4, a0 /* clear CP bit in CPENABLE */
- s16i a4, a2, XT_CPENABLE /* update old owner's CPENABLE */
- extui a4, a0, 16, 5 /* a4 = CP index = n */
- addx4 a5, a4, a5 /* a5 = &_xt_coproc_sa_offset[n] */
- /* Mark old owner state as saved (CPSTORED bit n set). */
- l16ui a4, a2, XT_CPSTORED /* a4 = old owner's CPSTORED */
- l32i a5, a5, 0 /* a5 = XT_CP[n]_SA offset */
- or a4, a4, a0 /* set CP in old owner's CPSTORED */
- s16i a4, a2, XT_CPSTORED /* update old owner's CPSTORED */
- l32i a2, a2, XT_CP_ASA /* ptr to actual (aligned) save area */
- extui a3, a0, 16, 5 /* a3 = CP index = n */
- add a2, a2, a5 /* a2 = old owner's area for CP n */
- /*
- The config-specific HAL macro invoked below destroys a2-5, preserves a0-1.
- It is theoretically possible for Xtensa processor designers to write TIE
- that causes more address registers to be affected, but it is generally
- unlikely. If that ever happens, more registers needs to be saved/restored
- around this macro invocation, and the value in a15 needs to be recomputed.
- */
- xchal_cpi_store_funcbody
- .L_check_new:
- /* Check if any state has to be restored for new owner. */
- /* NOTE: a15 = new owner's save area, cannot be zero when we get here. */
- beqz a15, .L_xt_coproc_done
- l16ui a3, a15, XT_CPSTORED /* a3 = new owner's CPSTORED */
- movi a4, _xt_coproc_sa_offset
- bnone a3, a0, .L_check_cs /* full CP not saved, check callee-saved */
- xor a3, a3, a0 /* CPSTORED bit is set, clear it */
- s16i a3, a15, XT_CPSTORED /* update new owner's CPSTORED */
- /* Adjust new owner's save area pointers to area for CP n. */
- extui a3, a0, 16, 5 /* a3 = CP index = n */
- addx4 a4, a3, a4 /* a4 = &_xt_coproc_sa_offset[n] */
- l32i a4, a4, 0 /* a4 = XT_CP[n]_SA */
- l32i a5, a15, XT_CP_ASA /* ptr to actual (aligned) save area */
- add a2, a4, a5 /* a2 = new owner's area for CP */
- /*
- The config-specific HAL macro invoked below destroys a2-5, preserves a0-1.
- It is theoretically possible for Xtensa processor designers to write TIE
- that causes more address registers to be affected, but it is generally
- unlikely. If that ever happens, more registers needs to be saved/restored
- around this macro invocation.
- */
- xchal_cpi_load_funcbody
- /* Restore interruptee's saved registers. */
- /* Can omit rsync for wsr.CPENABLE here because _xt_user_exit does it. */
- .L_xt_coproc_done:
- l32i a15, sp, XT_STK_A15
- #if portNUM_PROCESSORS > 1
- l32i a6, sp, XT_STK_A6
- l32i a7, sp, XT_STK_A7
- #endif /* portNUM_PROCESSORS > 1 */
- l32i a5, sp, XT_STK_A5
- l32i a4, sp, XT_STK_A4
- l32i a3, sp, XT_STK_A3
- l32i a2, sp, XT_STK_A2
- call0 _xt_user_exit /* return via exit dispatcher */
- /* Never returns here - call0 is used as a jump (see note at top) */
- .L_check_cs:
- /* a0 = CP mask in low bits, a15 = new owner's save area */
- l16ui a2, a15, XT_CP_CS_ST /* a2 = mask of CPs saved */
- bnone a2, a0, .L_xt_coproc_done /* if no match then done */
- and a2, a2, a0 /* a2 = which CPs to restore */
- extui a2, a2, 0, 8 /* extract low 8 bits */
- s32i a6, sp, XT_STK_A6 /* save extra needed regs */
- s32i a7, sp, XT_STK_A7
- s32i a13, sp, XT_STK_A13
- s32i a14, sp, XT_STK_A14
- call0 _xt_coproc_restorecs /* restore CP registers */
- l32i a6, sp, XT_STK_A6 /* restore saved registers */
- l32i a7, sp, XT_STK_A7
- l32i a13, sp, XT_STK_A13
- l32i a14, sp, XT_STK_A14
- j .L_xt_coproc_done
- /* Co-processor exception occurred outside a thread (not supported). */
- .L_xt_coproc_invalid:
- movi a0,PANIC_RSN_COPROCEXCEPTION
- wsr a0,EXCCAUSE
- call0 _xt_panic /* not in a thread (invalid) */
- /* never returns */
- #endif /* XCHAL_CP_NUM */
- /*
- -------------------------------------------------------------------------------
- Level 1 interrupt dispatch. Assumes stack frame has not been allocated yet.
- -------------------------------------------------------------------------------
- */
- .section .iram1,"ax"
- .type _xt_lowint1,@function
- .align 4
- _xt_lowint1:
- mov a0, sp /* sp == a1 */
- addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */
- s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */
- rsr a0, PS /* save interruptee's PS */
- s32i a0, sp, XT_STK_PS
- rsr a0, EPC_1 /* save interruptee's PC */
- s32i a0, sp, XT_STK_PC
- rsr a0, EXCSAVE_1 /* save interruptee's a0 */
- s32i a0, sp, XT_STK_A0
- movi a0, _xt_user_exit /* save exit point for dispatch */
- s32i a0, sp, XT_STK_EXIT
- /* EXCSAVE_1 should now be free to use. Use it to keep a copy of the
- current stack pointer that points to the exception frame (XT_STK_FRAME).*/
- #ifdef XT_DEBUG_BACKTRACE
- #ifndef __XTENSA_CALL0_ABI__
- mov a0, sp
- wsr a0, EXCSAVE_1
- #endif
- #endif
- /* Save rest of interrupt context and enter RTOS. */
- call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
- /* !! We are now on the RTOS system stack !! */
- /* Set up PS for C, enable interrupts above this level and clear EXCM. */
- #ifdef __XTENSA_CALL0_ABI__
- movi a0, PS_INTLEVEL(1) | PS_UM
- #else
- movi a0, PS_INTLEVEL(1) | PS_UM | PS_WOE
- #endif
- wsr a0, PS
- rsync
- /* OK to call C code at this point, dispatch user ISRs */
- dispatch_c_isr 1 XCHAL_INTLEVEL1_MASK
- /* Done handling interrupts, transfer control to OS */
- call0 XT_RTOS_INT_EXIT /* does not return directly here */
- /*
- -------------------------------------------------------------------------------
- MEDIUM PRIORITY (LEVEL 2+) INTERRUPT VECTORS AND LOW LEVEL HANDLERS.
- Medium priority interrupts are by definition those with priority greater
- than 1 and not greater than XCHAL_EXCM_LEVEL. These are disabled by
- setting PS.EXCM and therefore can easily support a C environment for
- handlers in C, and interact safely with an RTOS.
- Each vector goes at a predetermined location according to the Xtensa
- hardware configuration, which is ensured by its placement in a special
- section known to the Xtensa linker support package (LSP). It performs
- the minimum necessary before jumping to the handler in the .text section.
- The corresponding handler goes in the normal .text section. It sets up
- the appropriate stack frame, saves a few vector-specific registers and
- calls XT_RTOS_INT_ENTER to save the rest of the interrupted context
- and enter the RTOS, then sets up a C environment. It then calls the
- user's interrupt handler code (which may be coded in C) and finally
- calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling.
- While XT_RTOS_INT_EXIT does not return directly to the interruptee,
- eventually the RTOS scheduler will want to dispatch the interrupted
- task or handler. The scheduler will return to the exit point that was
- saved in the interrupt stack frame at XT_STK_EXIT.
- -------------------------------------------------------------------------------
- */
- #if XCHAL_EXCM_LEVEL >= 2
- .begin literal_prefix .Level2InterruptVector
- .section .Level2InterruptVector.text, "ax"
- .global _Level2Vector
- .type _Level2Vector,@function
- .align 4
- _Level2Vector:
- wsr a0, EXCSAVE_2 /* preserve a0 */
- call0 _xt_medint2 /* load interrupt handler */
- /* never returns here - call0 is used as a jump (see note at top) */
- .end literal_prefix
- .section .iram1,"ax"
- .type _xt_medint2,@function
- .align 4
- _xt_medint2:
- mov a0, sp /* sp == a1 */
- addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */
- s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */
- rsr a0, EPS_2 /* save interruptee's PS */
- s32i a0, sp, XT_STK_PS
- rsr a0, EPC_2 /* save interruptee's PC */
- s32i a0, sp, XT_STK_PC
- rsr a0, EXCSAVE_2 /* save interruptee's a0 */
- s32i a0, sp, XT_STK_A0
- movi a0, _xt_medint2_exit /* save exit point for dispatch */
- s32i a0, sp, XT_STK_EXIT
- /* EXCSAVE_2 should now be free to use. Use it to keep a copy of the
- current stack pointer that points to the exception frame (XT_STK_FRAME).*/
- #ifdef XT_DEBUG_BACKTRACE
- #ifndef __XTENSA_CALL0_ABI__
- mov a0, sp
- wsr a0, EXCSAVE_2
- #endif
- #endif
- /* Save rest of interrupt context and enter RTOS. */
- call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
- /* !! We are now on the RTOS system stack !! */
- /* Set up PS for C, enable interrupts above this level and clear EXCM. */
- #ifdef __XTENSA_CALL0_ABI__
- movi a0, PS_INTLEVEL(2) | PS_UM
- #else
- movi a0, PS_INTLEVEL(2) | PS_UM | PS_WOE
- #endif
- wsr a0, PS
- rsync
- /* OK to call C code at this point, dispatch user ISRs */
- dispatch_c_isr 2 XCHAL_INTLEVEL2_MASK
- /* Done handling interrupts, transfer control to OS */
- call0 XT_RTOS_INT_EXIT /* does not return directly here */
- /*
- Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
- on entry and used to return to a thread or interrupted interrupt handler.
- */
- .global _xt_medint2_exit
- .type _xt_medint2_exit,@function
- .align 4
- _xt_medint2_exit:
- /* Restore only level-specific regs (the rest were already restored) */
- l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
- wsr a0, EPS_2
- l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
- wsr a0, EPC_2
- l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
- l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */
- rsync /* ensure EPS and EPC written */
- rfi 2
- #endif /* Level 2 */
- #if XCHAL_EXCM_LEVEL >= 3
- .begin literal_prefix .Level3InterruptVector
- .section .Level3InterruptVector.text, "ax"
- .global _Level3Vector
- .type _Level3Vector,@function
- .align 4
- _Level3Vector:
- wsr a0, EXCSAVE_3 /* preserve a0 */
- call0 _xt_medint3 /* load interrupt handler */
- /* never returns here - call0 is used as a jump (see note at top) */
- .end literal_prefix
- .section .iram1,"ax"
- .type _xt_medint3,@function
- .align 4
- _xt_medint3:
- mov a0, sp /* sp == a1 */
- addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */
- s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */
- rsr a0, EPS_3 /* save interruptee's PS */
- s32i a0, sp, XT_STK_PS
- rsr a0, EPC_3 /* save interruptee's PC */
- s32i a0, sp, XT_STK_PC
- rsr a0, EXCSAVE_3 /* save interruptee's a0 */
- s32i a0, sp, XT_STK_A0
- movi a0, _xt_medint3_exit /* save exit point for dispatch */
- s32i a0, sp, XT_STK_EXIT
- /* EXCSAVE_3 should now be free to use. Use it to keep a copy of the
- current stack pointer that points to the exception frame (XT_STK_FRAME).*/
- #ifdef XT_DEBUG_BACKTRACE
- #ifndef __XTENSA_CALL0_ABI__
- mov a0, sp
- wsr a0, EXCSAVE_3
- #endif
- #endif
- /* Save rest of interrupt context and enter RTOS. */
- call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
- /* !! We are now on the RTOS system stack !! */
- /* Set up PS for C, enable interrupts above this level and clear EXCM. */
- #ifdef __XTENSA_CALL0_ABI__
- movi a0, PS_INTLEVEL(3) | PS_UM
- #else
- movi a0, PS_INTLEVEL(3) | PS_UM | PS_WOE
- #endif
- wsr a0, PS
- rsync
- /* OK to call C code at this point, dispatch user ISRs */
- dispatch_c_isr 3 XCHAL_INTLEVEL3_MASK
- /* Done handling interrupts, transfer control to OS */
- call0 XT_RTOS_INT_EXIT /* does not return directly here */
- /*
- Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
- on entry and used to return to a thread or interrupted interrupt handler.
- */
- .global _xt_medint3_exit
- .type _xt_medint3_exit,@function
- .align 4
- _xt_medint3_exit:
- /* Restore only level-specific regs (the rest were already restored) */
- l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
- wsr a0, EPS_3
- l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
- wsr a0, EPC_3
- l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
- l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */
- rsync /* ensure EPS and EPC written */
- rfi 3
- #endif /* Level 3 */
- #if XCHAL_EXCM_LEVEL >= 4
- .begin literal_prefix .Level4InterruptVector
- .section .Level4InterruptVector.text, "ax"
- .global _Level4Vector
- .type _Level4Vector,@function
- .align 4
- _Level4Vector:
- wsr a0, EXCSAVE_4 /* preserve a0 */
- call0 _xt_medint4 /* load interrupt handler */
- .end literal_prefix
- .section .iram1,"ax"
- .type _xt_medint4,@function
- .align 4
- _xt_medint4:
- mov a0, sp /* sp == a1 */
- addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */
- s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */
- rsr a0, EPS_4 /* save interruptee's PS */
- s32i a0, sp, XT_STK_PS
- rsr a0, EPC_4 /* save interruptee's PC */
- s32i a0, sp, XT_STK_PC
- rsr a0, EXCSAVE_4 /* save interruptee's a0 */
- s32i a0, sp, XT_STK_A0
- movi a0, _xt_medint4_exit /* save exit point for dispatch */
- s32i a0, sp, XT_STK_EXIT
- /* EXCSAVE_4 should now be free to use. Use it to keep a copy of the
- current stack pointer that points to the exception frame (XT_STK_FRAME).*/
- #ifdef XT_DEBUG_BACKTRACE
- #ifndef __XTENSA_CALL0_ABI__
- mov a0, sp
- wsr a0, EXCSAVE_4
- #endif
- #endif
- /* Save rest of interrupt context and enter RTOS. */
- call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
- /* !! We are now on the RTOS system stack !! */
- /* Set up PS for C, enable interrupts above this level and clear EXCM. */
- #ifdef __XTENSA_CALL0_ABI__
- movi a0, PS_INTLEVEL(4) | PS_UM
- #else
- movi a0, PS_INTLEVEL(4) | PS_UM | PS_WOE
- #endif
- wsr a0, PS
- rsync
- /* OK to call C code at this point, dispatch user ISRs */
- dispatch_c_isr 4 XCHAL_INTLEVEL4_MASK
- /* Done handling interrupts, transfer control to OS */
- call0 XT_RTOS_INT_EXIT /* does not return directly here */
- /*
- Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
- on entry and used to return to a thread or interrupted interrupt handler.
- */
- .global _xt_medint4_exit
- .type _xt_medint4_exit,@function
- .align 4
- _xt_medint4_exit:
- /* Restore only level-specific regs (the rest were already restored) */
- l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
- wsr a0, EPS_4
- l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
- wsr a0, EPC_4
- l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
- l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */
- rsync /* ensure EPS and EPC written */
- rfi 4
- #endif /* Level 4 */
- #if XCHAL_EXCM_LEVEL >= 5
- .begin literal_prefix .Level5InterruptVector
- .section .Level5InterruptVector.text, "ax"
- .global _Level5Vector
- .type _Level5Vector,@function
- .align 4
- _Level5Vector:
- wsr a0, EXCSAVE_5 /* preserve a0 */
- call0 _xt_medint5 /* load interrupt handler */
- .end literal_prefix
- .section .iram1,"ax"
- .type _xt_medint5,@function
- .align 4
- _xt_medint5:
- mov a0, sp /* sp == a1 */
- addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */
- s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */
- rsr a0, EPS_5 /* save interruptee's PS */
- s32i a0, sp, XT_STK_PS
- rsr a0, EPC_5 /* save interruptee's PC */
- s32i a0, sp, XT_STK_PC
- rsr a0, EXCSAVE_5 /* save interruptee's a0 */
- s32i a0, sp, XT_STK_A0
- movi a0, _xt_medint5_exit /* save exit point for dispatch */
- s32i a0, sp, XT_STK_EXIT
- /* EXCSAVE_5 should now be free to use. Use it to keep a copy of the
- current stack pointer that points to the exception frame (XT_STK_FRAME).*/
- #ifdef XT_DEBUG_BACKTRACE
- #ifndef __XTENSA_CALL0_ABI__
- mov a0, sp
- wsr a0, EXCSAVE_5
- #endif
- #endif
- /* Save rest of interrupt context and enter RTOS. */
- call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
- /* !! We are now on the RTOS system stack !! */
- /* Set up PS for C, enable interrupts above this level and clear EXCM. */
- #ifdef __XTENSA_CALL0_ABI__
- movi a0, PS_INTLEVEL(5) | PS_UM
- #else
- movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
- #endif
- wsr a0, PS
- rsync
- /* OK to call C code at this point, dispatch user ISRs */
- dispatch_c_isr 5 XCHAL_INTLEVEL5_MASK
- /* Done handling interrupts, transfer control to OS */
- call0 XT_RTOS_INT_EXIT /* does not return directly here */
- /*
- Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
- on entry and used to return to a thread or interrupted interrupt handler.
- */
- .global _xt_medint5_exit
- .type _xt_medint5_exit,@function
- .align 4
- _xt_medint5_exit:
- /* Restore only level-specific regs (the rest were already restored) */
- l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
- wsr a0, EPS_5
- l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
- wsr a0, EPC_5
- l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
- l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */
- rsync /* ensure EPS and EPC written */
- rfi 5
- #endif /* Level 5 */
- #if XCHAL_EXCM_LEVEL >= 6
- .begin literal_prefix .Level6InterruptVector
- .section .Level6InterruptVector.text, "ax"
- .global _Level6Vector
- .type _Level6Vector,@function
- .align 4
- _Level6Vector:
- wsr a0, EXCSAVE_6 /* preserve a0 */
- call0 _xt_medint6 /* load interrupt handler */
- .end literal_prefix
- .section .iram1,"ax"
- .type _xt_medint6,@function
- .align 4
- _xt_medint6:
- mov a0, sp /* sp == a1 */
- addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */
- s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */
- rsr a0, EPS_6 /* save interruptee's PS */
- s32i a0, sp, XT_STK_PS
- rsr a0, EPC_6 /* save interruptee's PC */
- s32i a0, sp, XT_STK_PC
- rsr a0, EXCSAVE_6 /* save interruptee's a0 */
- s32i a0, sp, XT_STK_A0
- movi a0, _xt_medint6_exit /* save exit point for dispatch */
- s32i a0, sp, XT_STK_EXIT
- /* EXCSAVE_6 should now be free to use. Use it to keep a copy of the
- current stack pointer that points to the exception frame (XT_STK_FRAME).*/
- #ifdef XT_DEBUG_BACKTRACE
- #ifndef __XTENSA_CALL0_ABI__
- mov a0, sp
- wsr a0, EXCSAVE_6
- #endif
- #endif
- /* Save rest of interrupt context and enter RTOS. */
- call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
- /* !! We are now on the RTOS system stack !! */
- /* Set up PS for C, enable interrupts above this level and clear EXCM. */
- #ifdef __XTENSA_CALL0_ABI__
- movi a0, PS_INTLEVEL(6) | PS_UM
- #else
- movi a0, PS_INTLEVEL(6) | PS_UM | PS_WOE
- #endif
- wsr a0, PS
- rsync
- /* OK to call C code at this point, dispatch user ISRs */
- dispatch_c_isr 6 XCHAL_INTLEVEL6_MASK
- /* Done handling interrupts, transfer control to OS */
- call0 XT_RTOS_INT_EXIT /* does not return directly here */
- /*
- Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT
- on entry and used to return to a thread or interrupted interrupt handler.
- */
- .global _xt_medint6_exit
- .type _xt_medint6_exit,@function
- .align 4
- _xt_medint6_exit:
- /* Restore only level-specific regs (the rest were already restored) */
- l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
- wsr a0, EPS_6
- l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
- wsr a0, EPC_6
- l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
- l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */
- rsync /* ensure EPS and EPC written */
- rfi 6
- #endif /* Level 6 */
- /*******************************************************************************
- HIGH PRIORITY (LEVEL > XCHAL_EXCM_LEVEL) INTERRUPT VECTORS AND HANDLERS
- High priority interrupts are by definition those with priorities greater
- than XCHAL_EXCM_LEVEL. This includes non-maskable (NMI). High priority
- interrupts cannot interact with the RTOS, that is they must save all regs
- they use and not call any RTOS function.
- A further restriction imposed by the Xtensa windowed architecture is that
- high priority interrupts must not modify the stack area even logically
- "above" the top of the interrupted stack (they need to provide their
- own stack or static save area).
- Cadence Design Systems recommends high priority interrupt handlers be coded in assembly
- and used for purposes requiring very short service times.
- Here are templates for high priority (level 2+) interrupt vectors.
- They assume only one interrupt per level to avoid the burden of identifying
- which interrupts at this level are pending and enabled. This allows for
- minimum latency and avoids having to save/restore a2 in addition to a0.
- If more than one interrupt per high priority level is configured, this burden
- is on the handler which in any case must provide a way to save and restore
- registers it uses without touching the interrupted stack.
- Each vector goes at a predetermined location according to the Xtensa
- hardware configuration, which is ensured by its placement in a special
- section known to the Xtensa linker support package (LSP). It performs
- the minimum necessary before jumping to the handler in the .text section.
- *******************************************************************************/
- /*
- Currently only shells for high priority interrupt handlers are provided
- here. However a template and example can be found in the Cadence Design Systems tools
- documentation: "Microprocessor Programmer's Guide".
- */
- #if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2
- .begin literal_prefix .Level2InterruptVector
- .section .Level2InterruptVector.text, "ax"
- .global _Level2Vector
- .type _Level2Vector,@function
- .global xt_highint2
- .align 4
- _Level2Vector:
- wsr a0, EXCSAVE_2 /* preserve a0 */
- call0 xt_highint2 /* load interrupt handler */
- .end literal_prefix
- .global xt_highint2
- .weak xt_highint2
- .set xt_highint2, _xt_highint2
- .section .iram1, "ax"
- .type _xt_highint2,@function
- .align 4
- _xt_highint2:
- #ifdef XT_INTEXC_HOOKS
- /* Call interrupt hook if present to (pre)handle interrupts. */
- movi a0, _xt_intexc_hooks
- l32i a0, a0, 2<<2
- beqz a0, 1f
- .Ln_xt_highint2_call_hook:
- callx0 a0 /* must NOT disturb stack! */
- 1:
- #endif
- /* USER_EDIT:
- ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE.
- */
- .align 4
- .L_xt_highint2_exit:
- rsr a0, EXCSAVE_2 /* restore a0 */
- rfi 2
- #endif /* Level 2 */
- #if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3
- .begin literal_prefix .Level3InterruptVector
- .section .Level3InterruptVector.text, "ax"
- .global _Level3Vector
- .type _Level3Vector,@function
- .global xt_highint3
- .align 4
- _Level3Vector:
- wsr a0, EXCSAVE_3 /* preserve a0 */
- call0 xt_highint3 /* load interrupt handler */
- /* never returns here - call0 is used as a jump (see note at top) */
- .end literal_prefix
- .global xt_highint3
- .weak xt_highint3
- .set xt_highint3, _xt_highint3
- .section .iram1, "ax"
- .type _xt_highint3,@function
- .align 4
- _xt_highint3:
- #ifdef XT_INTEXC_HOOKS
- /* Call interrupt hook if present to (pre)handle interrupts. */
- movi a0, _xt_intexc_hooks
- l32i a0, a0, 3<<2
- beqz a0, 1f
- .Ln_xt_highint3_call_hook:
- callx0 a0 /* must NOT disturb stack! */
- 1:
- #endif
- /* USER_EDIT:
- ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE.
- */
- .align 4
- .L_xt_highint3_exit:
- rsr a0, EXCSAVE_3 /* restore a0 */
- rfi 3
- #endif /* Level 3 */
- #if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4
- .begin literal_prefix .Level4InterruptVector
- .section .Level4InterruptVector.text, "ax"
- .global _Level4Vector
- .type _Level4Vector,@function
- .global xt_highint4
- .align 4
- _Level4Vector:
- wsr a0, EXCSAVE_4 /* preserve a0 */
- call0 xt_highint4 /* load interrupt handler */
- /* never returns here - call0 is used as a jump (see note at top) */
- .end literal_prefix
- .global xt_highint4
- .weak xt_highint4
- .set xt_highint4, _xt_highint4
- .section .iram1, "ax"
- .type _xt_highint4,@function
- .align 4
- _xt_highint4:
- #ifdef XT_INTEXC_HOOKS
- /* Call interrupt hook if present to (pre)handle interrupts. */
- movi a0, _xt_intexc_hooks
- l32i a0, a0, 4<<2
- beqz a0, 1f
- .Ln_xt_highint4_call_hook:
- callx0 a0 /* must NOT disturb stack! */
- 1:
- #endif
- /* USER_EDIT:
- ADD HIGH PRIORITY LEVEL 4 INTERRUPT HANDLER CODE HERE.
- */
- .align 4
- .L_xt_highint4_exit:
- rsr a0, EXCSAVE_4 /* restore a0 */
- rfi 4
- #endif /* Level 4 */
- #if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5
- .begin literal_prefix .Level5InterruptVector
- .section .Level5InterruptVector.text, "ax"
- .global _Level5Vector
- .type _Level5Vector,@function
- .global xt_highint5
- .align 4
- _Level5Vector:
- wsr a0, EXCSAVE_5 /* preserve a0 */
- call0 xt_highint5 /* load interrupt handler */
- /* never returns here - call0 is used as a jump (see note at top) */
- .end literal_prefix
- .global xt_highint5
- .weak xt_highint5
- .set xt_highint5, _xt_highint5
- .section .iram1, "ax"
- .type _xt_highint5,@function
- .align 4
- _xt_highint5:
- #ifdef XT_INTEXC_HOOKS
- /* Call interrupt hook if present to (pre)handle interrupts. */
- movi a0, _xt_intexc_hooks
- l32i a0, a0, 5<<2
- beqz a0, 1f
- .Ln_xt_highint5_call_hook:
- callx0 a0 /* must NOT disturb stack! */
- 1:
- #endif
- /* USER_EDIT:
- ADD HIGH PRIORITY LEVEL 5 INTERRUPT HANDLER CODE HERE.
- */
- .align 4
- .L_xt_highint5_exit:
- rsr a0, EXCSAVE_5 /* restore a0 */
- rfi 5
- #endif /* Level 5 */
- #if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6
- .begin literal_prefix .Level6InterruptVector
- .section .Level6InterruptVector.text, "ax"
- .global _Level6Vector
- .type _Level6Vector,@function
- .global xt_highint6
- .align 4
- _Level6Vector:
- wsr a0, EXCSAVE_6 /* preserve a0 */
- call0 xt_highint6 /* load interrupt handler */
- /* never returns here - call0 is used as a jump (see note at top) */
- .end literal_prefix
- .global xt_highint6
- .weak xt_highint6
- .set xt_highint6, _xt_highint6
- .section .iram1, "ax"
- .type _xt_highint6,@function
- .align 4
- _xt_highint6:
- #ifdef XT_INTEXC_HOOKS
- /* Call interrupt hook if present to (pre)handle interrupts. */
- movi a0, _xt_intexc_hooks
- l32i a0, a0, 6<<2
- beqz a0, 1f
- .Ln_xt_highint6_call_hook:
- callx0 a0 /* must NOT disturb stack! */
- 1:
- #endif
- /* USER_EDIT:
- ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE.
- */
- .align 4
- .L_xt_highint6_exit:
- rsr a0, EXCSAVE_6 /* restore a0 */
- rfi 6
- #endif /* Level 6 */
- #if XCHAL_HAVE_NMI
- .begin literal_prefix .NMIExceptionVector
- .section .NMIExceptionVector.text, "ax"
- .global _NMIExceptionVector
- .type _NMIExceptionVector,@function
- .global xt_nmi
- .align 4
- _NMIExceptionVector:
- wsr a0, EXCSAVE + XCHAL_NMILEVEL /* preserve a0 */
- call0 xt_nmi /* load interrupt handler */
- /* never returns here - call0 is used as a jump (see note at top) */
- .end literal_prefix
- .global xt_nmi
- .weak xt_nmi
- .set xt_nmi, _xt_nmi
- .section .iram1, "ax"
- .type _xt_nmi,@function
- .align 4
- _xt_nmi:
- #ifdef XT_INTEXC_HOOKS
- /* Call interrupt hook if present to (pre)handle interrupts. */
- movi a0, _xt_intexc_hooks
- l32i a0, a0, XCHAL_NMILEVEL<<2
- beqz a0, 1f
- .Ln_xt_nmi_call_hook:
- callx0 a0 /* must NOT disturb stack! */
- 1:
- #endif
- /* USER_EDIT:
- ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE.
- */
- .align 4
- .L_xt_nmi_exit:
- rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */
- rfi XCHAL_NMILEVEL
- #endif /* NMI */
- /*******************************************************************************
- WINDOW OVERFLOW AND UNDERFLOW EXCEPTION VECTORS AND ALLOCA EXCEPTION HANDLER
- Here is the code for each window overflow/underflow exception vector and
- (interspersed) efficient code for handling the alloca exception cause.
- Window exceptions are handled entirely in the vector area and are very
- tight for performance. The alloca exception is also handled entirely in
- the window vector area so comes at essentially no cost in code size.
- Users should never need to modify them and Cadence Design Systems recommends
- they do not.
- Window handlers go at predetermined vector locations according to the
- Xtensa hardware configuration, which is ensured by their placement in a
- special section known to the Xtensa linker support package (LSP). Since
- their offsets in that section are always the same, the LSPs do not define
- a section per vector.
- These things are coded for XEA2 only (XEA1 is not supported).
- Note on Underflow Handlers:
- The underflow handler for returning from call[i+1] to call[i]
- must preserve all the registers from call[i+1]'s window.
- In particular, a0 and a1 must be preserved because the RETW instruction
- will be reexecuted (and may even underflow if an intervening exception
- has flushed call[i]'s registers).
- Registers a2 and up may contain return values.
- *******************************************************************************/
- #if XCHAL_HAVE_WINDOWED
- .section .WindowVectors.text, "ax"
- /*
- --------------------------------------------------------------------------------
- Window Overflow Exception for Call4.
- Invoked if a call[i] referenced a register (a4-a15)
- that contains data from ancestor call[j];
- call[j] had done a call4 to call[j+1].
- On entry here:
- window rotated to call[j] start point;
- a0-a3 are registers to be saved;
- a4-a15 must be preserved;
- a5 is call[j+1]'s stack pointer.
- --------------------------------------------------------------------------------
- */
- .org 0x0
- .global _WindowOverflow4
- _WindowOverflow4:
- s32e a0, a5, -16 /* save a0 to call[j+1]'s stack frame */
- s32e a1, a5, -12 /* save a1 to call[j+1]'s stack frame */
- s32e a2, a5, -8 /* save a2 to call[j+1]'s stack frame */
- s32e a3, a5, -4 /* save a3 to call[j+1]'s stack frame */
- rfwo /* rotates back to call[i] position */
- /*
- --------------------------------------------------------------------------------
- Window Underflow Exception for Call4
- Invoked by RETW returning from call[i+1] to call[i]
- where call[i]'s registers must be reloaded (not live in ARs);
- where call[i] had done a call4 to call[i+1].
- On entry here:
- window rotated to call[i] start point;
- a0-a3 are undefined, must be reloaded with call[i].reg[0..3];
- a4-a15 must be preserved (they are call[i+1].reg[0..11]);
- a5 is call[i+1]'s stack pointer.
- --------------------------------------------------------------------------------
- */
- .org 0x40
- .global _WindowUnderflow4
- _WindowUnderflow4:
- l32e a0, a5, -16 /* restore a0 from call[i+1]'s stack frame */
- l32e a1, a5, -12 /* restore a1 from call[i+1]'s stack frame */
- l32e a2, a5, -8 /* restore a2 from call[i+1]'s stack frame */
- l32e a3, a5, -4 /* restore a3 from call[i+1]'s stack frame */
- rfwu
- /*
- --------------------------------------------------------------------------------
- Handle alloca exception generated by interruptee executing 'movsp'.
- This uses space between the window vectors, so is essentially "free".
- All interruptee's regs are intact except a0 which is saved in EXCSAVE_1,
- and PS.EXCM has been set by the exception hardware (can't be interrupted).
- The fact the alloca exception was taken means the registers associated with
- the base-save area have been spilled and will be restored by the underflow
- handler, so those 4 registers are available for scratch.
- The code is optimized to avoid unaligned branches and minimize cache misses.
- --------------------------------------------------------------------------------
- */
- .align 4
- .global _xt_alloca_exc
- _xt_alloca_exc:
- rsr a0, WINDOWBASE /* grab WINDOWBASE before rotw changes it */
- rotw -1 /* WINDOWBASE goes to a4, new a0-a3 are scratch */
- rsr a2, PS
- extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS
- xor a3, a3, a4 /* bits changed from old to current windowbase */
- rsr a4, EXCSAVE_1 /* restore original a0 (now in a4) */
- slli a3, a3, XCHAL_PS_OWB_SHIFT
- xor a2, a2, a3 /* flip changed bits in old window base */
- wsr a2, PS /* update PS.OWB to new window base */
- rsync
- bbci.l a4, 31, _WindowUnderflow4
- rotw -1 /* original a0 goes to a8 */
- bbci.l a8, 30, _WindowUnderflow8
- rotw -1
- j _WindowUnderflow12
- /*
- --------------------------------------------------------------------------------
- Window Overflow Exception for Call8
- Invoked if a call[i] referenced a register (a4-a15)
- that contains data from ancestor call[j];
- call[j] had done a call8 to call[j+1].
- On entry here:
- window rotated to call[j] start point;
- a0-a7 are registers to be saved;
- a8-a15 must be preserved;
- a9 is call[j+1]'s stack pointer.
- --------------------------------------------------------------------------------
- */
- .org 0x80
- .global _WindowOverflow8
- _WindowOverflow8:
- s32e a0, a9, -16 /* save a0 to call[j+1]'s stack frame */
- l32e a0, a1, -12 /* a0 <- call[j-1]'s sp
- (used to find end of call[j]'s frame) */
- s32e a1, a9, -12 /* save a1 to call[j+1]'s stack frame */
- s32e a2, a9, -8 /* save a2 to call[j+1]'s stack frame */
- s32e a3, a9, -4 /* save a3 to call[j+1]'s stack frame */
- s32e a4, a0, -32 /* save a4 to call[j]'s stack frame */
- s32e a5, a0, -28 /* save a5 to call[j]'s stack frame */
- s32e a6, a0, -24 /* save a6 to call[j]'s stack frame */
- s32e a7, a0, -20 /* save a7 to call[j]'s stack frame */
- rfwo /* rotates back to call[i] position */
- /*
- --------------------------------------------------------------------------------
- Window Underflow Exception for Call8
- Invoked by RETW returning from call[i+1] to call[i]
- where call[i]'s registers must be reloaded (not live in ARs);
- where call[i] had done a call8 to call[i+1].
- On entry here:
- window rotated to call[i] start point;
- a0-a7 are undefined, must be reloaded with call[i].reg[0..7];
- a8-a15 must be preserved (they are call[i+1].reg[0..7]);
- a9 is call[i+1]'s stack pointer.
- --------------------------------------------------------------------------------
- */
- .org 0xC0
- .global _WindowUnderflow8
- _WindowUnderflow8:
- l32e a0, a9, -16 /* restore a0 from call[i+1]'s stack frame */
- l32e a1, a9, -12 /* restore a1 from call[i+1]'s stack frame */
- l32e a2, a9, -8 /* restore a2 from call[i+1]'s stack frame */
- l32e a7, a1, -12 /* a7 <- call[i-1]'s sp
- (used to find end of call[i]'s frame) */
- l32e a3, a9, -4 /* restore a3 from call[i+1]'s stack frame */
- l32e a4, a7, -32 /* restore a4 from call[i]'s stack frame */
- l32e a5, a7, -28 /* restore a5 from call[i]'s stack frame */
- l32e a6, a7, -24 /* restore a6 from call[i]'s stack frame */
- l32e a7, a7, -20 /* restore a7 from call[i]'s stack frame */
- rfwu
- /*
- --------------------------------------------------------------------------------
- Window Overflow Exception for Call12
- Invoked if a call[i] referenced a register (a4-a15)
- that contains data from ancestor call[j];
- call[j] had done a call12 to call[j+1].
- On entry here:
- window rotated to call[j] start point;
- a0-a11 are registers to be saved;
- a12-a15 must be preserved;
- a13 is call[j+1]'s stack pointer.
- --------------------------------------------------------------------------------
- */
- .org 0x100
- .global _WindowOverflow12
- _WindowOverflow12:
- s32e a0, a13, -16 /* save a0 to call[j+1]'s stack frame */
- l32e a0, a1, -12 /* a0 <- call[j-1]'s sp
- (used to find end of call[j]'s frame) */
- s32e a1, a13, -12 /* save a1 to call[j+1]'s stack frame */
- s32e a2, a13, -8 /* save a2 to call[j+1]'s stack frame */
- s32e a3, a13, -4 /* save a3 to call[j+1]'s stack frame */
- s32e a4, a0, -48 /* save a4 to end of call[j]'s stack frame */
- s32e a5, a0, -44 /* save a5 to end of call[j]'s stack frame */
- s32e a6, a0, -40 /* save a6 to end of call[j]'s stack frame */
- s32e a7, a0, -36 /* save a7 to end of call[j]'s stack frame */
- s32e a8, a0, -32 /* save a8 to end of call[j]'s stack frame */
- s32e a9, a0, -28 /* save a9 to end of call[j]'s stack frame */
- s32e a10, a0, -24 /* save a10 to end of call[j]'s stack frame */
- s32e a11, a0, -20 /* save a11 to end of call[j]'s stack frame */
- rfwo /* rotates back to call[i] position */
- /*
- --------------------------------------------------------------------------------
- Window Underflow Exception for Call12
- Invoked by RETW returning from call[i+1] to call[i]
- where call[i]'s registers must be reloaded (not live in ARs);
- where call[i] had done a call12 to call[i+1].
- On entry here:
- window rotated to call[i] start point;
- a0-a11 are undefined, must be reloaded with call[i].reg[0..11];
- a12-a15 must be preserved (they are call[i+1].reg[0..3]);
- a13 is call[i+1]'s stack pointer.
- --------------------------------------------------------------------------------
- */
- .org 0x140
- .global _WindowUnderflow12
- _WindowUnderflow12:
- l32e a0, a13, -16 /* restore a0 from call[i+1]'s stack frame */
- l32e a1, a13, -12 /* restore a1 from call[i+1]'s stack frame */
- l32e a2, a13, -8 /* restore a2 from call[i+1]'s stack frame */
- l32e a11, a1, -12 /* a11 <- call[i-1]'s sp
- (used to find end of call[i]'s frame) */
- l32e a3, a13, -4 /* restore a3 from call[i+1]'s stack frame */
- l32e a4, a11, -48 /* restore a4 from end of call[i]'s stack frame */
- l32e a5, a11, -44 /* restore a5 from end of call[i]'s stack frame */
- l32e a6, a11, -40 /* restore a6 from end of call[i]'s stack frame */
- l32e a7, a11, -36 /* restore a7 from end of call[i]'s stack frame */
- l32e a8, a11, -32 /* restore a8 from end of call[i]'s stack frame */
- l32e a9, a11, -28 /* restore a9 from end of call[i]'s stack frame */
- l32e a10, a11, -24 /* restore a10 from end of call[i]'s stack frame */
- l32e a11, a11, -20 /* restore a11 from end of call[i]'s stack frame */
- rfwu
- #endif /* XCHAL_HAVE_WINDOWED */
- .section .UserEnter.text, "ax"
- .global call_user_start
- .type call_user_start,@function
- .align 4
- .literal_position
|