393 lines
17 KiB
ArmAsm
393 lines
17 KiB
ArmAsm
/**************************************************************************/
|
|
/* Copyright (c) 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. */
|
|
/**************************************************************************/
|
|
|
|
/**************************************************************************/
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* Xtensa exception and interrupt dispatch for XEA3. */
|
|
/* */
|
|
/* 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 calling the user's specific interrupt handlers. */
|
|
/* */
|
|
/* Users can install application-specific interrupt handlers by calling */
|
|
/* xt_set_interrupt_handler(). These handlers can be written in C and */
|
|
/* must follow the C calling convention. The handler table is indexed by */
|
|
/* the interrupt number. Each handler may be provided with an argument. */
|
|
/* */
|
|
/* Users can 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. These are the alloca, syscall, and coprocessor */
|
|
/* exceptions. */
|
|
/* */
|
|
/* 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. */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 12-31-2020 Cadence Design Systems Initial Version 6.1.3 */
|
|
/* */
|
|
/**************************************************************************/
|
|
|
|
|
|
#include <xtensa/config/core.h>
|
|
#include <xtensa/coreasm.h>
|
|
|
|
#if XCHAL_HAVE_XEA3
|
|
|
|
#include "xtensa_context.h"
|
|
|
|
#if (XCHAL_HW_VERSION < XTENSA_HWVERSION_RH_2016_2)
|
|
#error Xtensa HW earlier than RH_2016.2 not supported.
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The entry point vectors are common for call0 and windowed configurations.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
.extern _DoubleExceptionHandler
|
|
.extern _xtos_exc_dispatch
|
|
|
|
.section .DispatchVector.text, "ax"
|
|
#if XCHAL_HAVE_VECBASE
|
|
.align 64 // 64-byte alignment needed when vecbase
|
|
#else // is relocatable
|
|
.align 4
|
|
#endif
|
|
|
|
.org 0 // Fixed offset for Reset Vector
|
|
.global _DispatchVector
|
|
.weak _DispatchVector
|
|
|
|
_DispatchVector:
|
|
j _JumpToResetHandler
|
|
|
|
.org 3 // Reserved
|
|
.local _Reserved1
|
|
|
|
_Reserved1:
|
|
ill
|
|
|
|
.org 6 // Fixed offset for Double Exception Vector
|
|
.global _DoubleExceptionVector
|
|
.weak _DoubleExceptionVector
|
|
|
|
_DoubleExceptionVector:
|
|
j _DoubleExceptionHandler
|
|
|
|
.org 9 // Reserved
|
|
.local _Reserved2
|
|
|
|
_Reserved2:
|
|
ill
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Start of dispatch code.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
.org 12 // Fixed offset for Tailchain entry point
|
|
.global _xt_dispatch
|
|
|
|
_xt_dispatch:
|
|
#ifdef __XTENSA_CALL0_ABI__
|
|
|
|
// NOTE: for call0, a15 is expected to be holding the previous stack pointer
|
|
// when we get to the Tailchain segment.
|
|
|
|
s32si.x4 a2, a15 // Select interrupt, a2 <- (intnum << 2)
|
|
movi a0, 0
|
|
l32dis.it a0, a0 // a0 <- wrapper addr (handler_table[0])
|
|
s32stk a9, a15, 96 // Set new stack pointer
|
|
#if XT_STK_XTRA_SZ
|
|
addi a1, a1, -XT_STK_XTRA_SZ // Adjust for extra save area
|
|
#endif
|
|
s32dis.h a0, a0 // Jump to handler if interrupt else fall through
|
|
// Note this also clears local exclusive monitor
|
|
|
|
#else // windowed
|
|
|
|
s32si.x4 a10, a1 // Select interrupt, a10 <- (intnum << 2)
|
|
movi a8, 0
|
|
l32dis.it a8, a8 // a8 <- wrapper addr (handler_table[0])
|
|
s32stk a9, a1, 96 // Set new stack pointer
|
|
#if XT_STK_XTRA_SZ
|
|
addi a9, a9, -XT_STK_XTRA_SZ // Adjust for extra save area
|
|
#endif
|
|
s32dis.h a8, a8 // Jump to handler if interrupt else fall through
|
|
// Note this also clears local exclusive monitor
|
|
|
|
#endif // __XTENSA_CALL0_ABI__
|
|
|
|
.Lexit:
|
|
j _xt_exit
|
|
|
|
#ifndef __XTENSA_CALL0_ABI__
|
|
.org 36 // Fixed offset for Underflow segment
|
|
.global _xt_underflow
|
|
|
|
_xt_underflow:
|
|
l32e a8, a1, -64 // a8 <- [a1-32]
|
|
l32e a9, a1, -64 // a9 <- [a1-28]
|
|
l32e a10, a1, -64 // a10 <- [a1-24]
|
|
l32e a11, a1, -64 // a11 <- [a1-20]
|
|
l32e a12, a1, -64 // a12 <- [a1-16]
|
|
l32e a13, a1, -64 // a13 <- [a1-12]
|
|
l32e a14, a1, -64 // a14 <- [a1-8]
|
|
l32e a15, a1, -64 // a15 <- [a1-4] ; Return (branch to EPC)
|
|
#endif
|
|
|
|
.org 60 // Fixed offset for Save/Overflow segment
|
|
.global _xt_save
|
|
|
|
_xt_save:
|
|
#ifdef __XTENSA_CALL0_ABI__
|
|
s32e a0, a1, -64 // [a1-64] <- a0
|
|
s32e a2, a1, -48 // [a1-56] <- a2 ; a2 <- EPC
|
|
s32e a3, a1, -64 // [a1-52] <- a3
|
|
s32e a4, a1, -64 // [a1-48] <- a4
|
|
s32e a5, a1, -64 // [a1-44] <- a5
|
|
s32e a6, a1, -64 // [a1-40] <- a6
|
|
s32e a7, a1, -64 // [a1-36] <- a7
|
|
#else
|
|
.global _xt_overflow
|
|
_xt_overflow:
|
|
#endif
|
|
s32e a8, a1, -52 // [a1-32] <- a8 ; a8 <- ExcVAddr
|
|
s32e a9, a1, -28 // [a1-28] <- a9 ; a9 <- PS/SAR
|
|
s32e a10, a1, -48 // [a1-24] <- a10 ; a10 <- EPC
|
|
s32e a11, a1, -24 // [a1-20] <- a11 ; a11 <- ExcCause
|
|
s32e a12, a1, -44 // [a1-16] <- a12 ; a12 <- LBEG
|
|
s32e a13, a1, -40 // [a1-12] <- a13 ; a13 <- LEND
|
|
s32e a14, a1, -36 // [a1-8] <- a14 ; a14 <- LCOUNT
|
|
s32e a15, a1, -32 // [a1-4] <- a15 ; a15 <- a1
|
|
// If Overflow then return (branch to EPC)
|
|
|
|
_xt_entry:
|
|
s32e a8, a1, -4 // [a1-68] <- a8 (ExcVAddr)
|
|
s32e a11, a1, -8 // [a1-72] <- a11 (ExcCause)
|
|
#if XCHAL_HAVE_LOOPS
|
|
s32e a12, a1, -20 // [a1-84] <- a12 (LBEG)
|
|
s32e a13, a1, -24 // [a1-88] <- a13 (LEND)
|
|
s32e a14, a1, -28 // [a1-92] <- a14 (LCOUNT)
|
|
#endif
|
|
#if XCHAL_HAVE_EXCLUSIVE
|
|
movi a12, 0
|
|
getex a12
|
|
s32e a12, a1, -32 // [a1-96] <- a12 (ATOMCTL)
|
|
#endif
|
|
|
|
j 1f // make room for literals
|
|
|
|
.align 4
|
|
.literal_position
|
|
|
|
.Le1:
|
|
.word _xt_exception_table
|
|
|
|
1:
|
|
// Call OS-specific code for additional work to be done. Stay on interruptee's
|
|
// stack in case more saves are required into stack frame.
|
|
// NOTE: OS-specific code can use a8, a12-a14, (+a2-a7: call0, a15: windowed).
|
|
// ALL other registers must be preserved.
|
|
|
|
XT_RTOS_INT_ENTER
|
|
|
|
// This sequence checks the interrupt controller and loads the interrupt
|
|
// number if available, and also loads the wrapper handler address.
|
|
// If there is an interrupt, execution will branch to the wrapper which
|
|
// will then forward to the correct handler.
|
|
// All this happens only if there is a pending interrupt. If not, execution
|
|
// falls through to exception handling.
|
|
|
|
#ifdef __XTENSA_CALL0_ABI__
|
|
|
|
s32si.x4 a2, a1 // [a1-80] <- a2 (EPC) ; a2 <- (intnum << 2)
|
|
movi a0, 0
|
|
l32dis.it a0, a0 // a0 <- wrapper addr (handler_table[0])
|
|
s32stk a9, a1, 96 // [a1-76] <- a9 (PS/SAR) ; a1 = a1-96
|
|
#if XT_STK_XTRA_SZ
|
|
addi a1, a1, -XT_STK_XTRA_SZ // Adjust for extra save area
|
|
#endif
|
|
s32dis.h a0, a0 // Jump to handler if interrupt else fall through
|
|
|
|
#else // windowed
|
|
|
|
s32si.x4 a10, a1 // [a1-80] <- a10 (EPC) ; a10 <- (intnum << 2)
|
|
movi a8, 0
|
|
l32dis.it a8, a8 // a8 <- wrapper addr (handler_table[0])
|
|
s32stk a9, a1, 96 // [a1-76] <- a9 (PS/SAR) ; a9 = a1-96
|
|
#if XT_STK_XTRA_SZ
|
|
addi a9, a9, -XT_STK_XTRA_SZ // Adjust for extra save area
|
|
#endif
|
|
s32dis.h a8, a8 // Jump to handler if interrupt else fall through
|
|
|
|
#endif // __XTENSA_CALL0_ABI__
|
|
|
|
// At this point we have:
|
|
// (note window has rotated for windowed ABI)
|
|
// a0 holds return address (Tailchain+3)
|
|
// For call0:
|
|
// a11 holds ExcCause, also saved in [oldsp - 72]
|
|
// a15 holds exception SP, a1 points to exception frame
|
|
// For windowed:
|
|
// a3 holds ExcCause, also saved in [oldsp - 72]
|
|
// a1 points to exception frame
|
|
|
|
.global _xt_exception
|
|
|
|
_xt_exception:
|
|
l32r a2, .Le1 // Load exc table address
|
|
#ifdef __XTENSA_CALL0_ABI__
|
|
mov a3, a11 // Copy exception cause to a3
|
|
#endif
|
|
extui a4, a3, 0, 4 // Extract exception cause
|
|
addx4 a2, a4, a2 // Index into exc table
|
|
l32i a4, a2, 0 // Load handler address
|
|
#if XT_STK_XTRA_SZ
|
|
addi a2, a1, XT_STK_XTRA_SZ // Argument = Exception frame ptr
|
|
#else
|
|
mov a2, a1 // Argument = Exception frame ptr
|
|
#endif
|
|
jx a4 // Return directly from handler
|
|
|
|
// Exit/restore sequence
|
|
|
|
.global _xt_exit
|
|
|
|
_xt_exit:
|
|
#ifdef __XTENSA_CALL0_ABI__
|
|
mov a1, a15 // Restore stack pointer
|
|
#endif
|
|
|
|
// Run OS-specific code to determine what to restore.
|
|
// Interrupts will remain disabled through this sequence.
|
|
// WARNING: stack pointer may change within this macro
|
|
// so all restores off the stack must happen afterwards.
|
|
|
|
XT_RTOS_INT_EXIT
|
|
|
|
.global _xt_restore
|
|
|
|
_xt_restore:
|
|
// Some loads must happen before DISPST = Restore, as these
|
|
// will not be accessible via L32E once DISPST = Restore.
|
|
|
|
#if XCHAL_HAVE_EXCLUSIVE
|
|
l32e a12, a1, -32 // a12 <- [a1-96] (ATOMCTL)
|
|
getex a12
|
|
#endif
|
|
l32e a10, a1, -12 // a10 <- [a1-76] (PS/SAR)
|
|
l32e a12, a1, -20 // a12 <- [a1-84] (LBEG)
|
|
l32e a13, a1, -24 // a13 <- [a1-88] (LEND)
|
|
l32e a14, a1, -28 // a14 <- [a1-92] (LCOUNT)
|
|
l32dis.epc a11, a1 // a11 <- [a1-80] (EPC)
|
|
// If interrupt goto tailchain else fall through
|
|
|
|
#ifdef __XTENSA_CALL0_ABI__
|
|
l32e a0, a1, -64 // a0 <- [a1-64]
|
|
l32e a2, a1, -64 // a2 <- [a1-56]
|
|
l32e a3, a1, -64 // a3 <- [a1-52]
|
|
l32e a4, a1, -64 // a4 <- [a1-48]
|
|
l32e a5, a1, -64 // a5 <- [a1-44]
|
|
l32e a6, a1, -64 // a6 <- [a1-40]
|
|
l32e a7, a1, -64 // a7 <- [a1-36]
|
|
#endif
|
|
|
|
// Important: the following restrictions must be observed:
|
|
// 1) The LCOUNT register must be restored after LBEG/LEND.
|
|
// 2) There must be at least 3 instructions between the LCOUNT
|
|
// restore and the last L32E (the one that branches).
|
|
|
|
l32e a12, a1, -44 // LBEG <- a12, a12 <- [a1-16]
|
|
l32e a13, a1, -40 // LEND <- a13, a13 <- [a1-12]
|
|
l32e a14, a1, -36 // LCOUNT <- a14, a14 <- [a1-8]
|
|
l32e a8, a1, -64 // a8 <- [a1-32]
|
|
l32e a9, a1, -64 // a9 <- [a1-28]
|
|
l32e a10, a1, -60 // PS/SAR <- a10, a10 <- [a1-24]
|
|
l32e a11, a1, -48 // EPC <- a11, a11 <- [a1-20]
|
|
l32e a15, a1, -64 // a15 <- [a1-4], Branch to EPC if no interrupt
|
|
// If interrupt, branch to Tailchain
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Branch to reset handler code from here. Use CALL0 as a branch, will expand
|
|
// to CALLX0 if needed when built with the -mlongcalls option.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
.align 4
|
|
.local _JumpToResetHandler
|
|
|
|
_JumpToResetHandler:
|
|
call0 _ResetHandler
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Idle loop. On interrupt, no state needs saving.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
.align 4
|
|
.global _xt_idle
|
|
|
|
_xt_idle:
|
|
movi a14, _xt_interrupt_stack_top
|
|
mov a1, a14 // a1 <- Top of interrupt stack
|
|
movi a14, 0 // 0 = Normal
|
|
wsr.ms a14 // Set DISPST = Normal
|
|
rsync
|
|
waiti 0 // Wait for interrupt
|
|
memw // HW erratum 569
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Scheduler interrupt handler. Triggered by context switch. At this time only
|
|
// useful for windowed ABI to spill register windows.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
.align 4
|
|
.global xt_sched_handler
|
|
|
|
xt_sched_handler:
|
|
#ifdef __XTENSA_WINDOWED_ABI__
|
|
entry a1, 32
|
|
ssai 1
|
|
spillw
|
|
retw
|
|
#else
|
|
ret
|
|
#endif
|
|
|
|
#endif // XCHAL_HAVE_XEA3
|
|
|