| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230 |
- /*
- * 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 */
- #if portNUM_PROCESSORS == 1
- s32i a6, sp, XT_STK_A6 /* save extra needed regs */
- s32i a7, sp, XT_STK_A7
- #endif /* portNUM_PROCESSORS == 1 */
- s32i a13, sp, XT_STK_A13
- s32i a14, sp, XT_STK_A14
- call0 _xt_coproc_restorecs /* restore CP registers */
- #if portNUM_PROCESSORS == 1
- l32i a6, sp, XT_STK_A6 /* restore saved registers */
- l32i a7, sp, XT_STK_A7
- #endif /* portNUM_PROCESSORS == 1 */
- 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
|