/*
 * 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.
 */

#include <xtensa/config/core-isa.h>
#include <syscalls.h>

//#define PS_OWB_SHIFT 8
//#define PS_OWB_BITS 4
//#define EXCCAUSE_ALLOCA			5	/* Stack Extension Assist (MOVSP instruction) for alloca */

#if XCHAL_HAVE_L32R
    .section .rodata
_sim_panic_msg:
    .ascii "PANIC: Unhandled exception!\n"
	_sim_panic_msg_len = . - _sim_panic_msg

    .section .text
    .literal .Lpanic_msg, _sim_panic_msg
    .literal .Lpanic_msg_len, _sim_panic_msg_len
    .align      4
_xt_unhandled_exc:
    movi a2, SYS_write
    movi a3, 2
    l32r a4, .Lpanic_msg
    l32r a5, .Lpanic_msg_len
    simcall
#else
_xt_unhandled_exc:
#endif
    movi a2, SYS_exit
    movi a3, 1
    simcall

/*
--------------------------------------------------------------------------------
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.
--------------------------------------------------------------------------------
*/

    #if XCHAL_HAVE_WINDOWED
    .section .text
    .global _xt_alloca_exc
    .align  4
_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, 8/*PS_OWB_BITS*/, 4/*PS_OWB_BITS*/
    xor     a3, a3, a4      /* bits changed from old to current windowbase */
    rsr     a4, EXCSAVE1   /* restore original a0 (now in a4) */
    slli    a3, a3, 8
    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
    #endif


/*
--------------------------------------------------------------------------------
  User exception handler.
--------------------------------------------------------------------------------
*/

    #if XCHAL_HAVE_WINDOWED
    .section .text
    .align      4
_xt_to_alloca_exc:
    j   _xt_alloca_exc                  /* in window vectors section */
    #endif

    .type       _xt_user_exc,@function
    .align      4
_xt_user_exc:

    rsr     a0, EXCCAUSE
    /* Handle alloca and syscall exceptions */
    #if XCHAL_HAVE_WINDOWED
    beqi    a0, 5/*EXCCAUSE_ALLOCA*/,  _xt_to_alloca_exc
    #endif
    j _xt_unhandled_exc


/*
--------------------------------------------------------------------------------
NMI Exception
--------------------------------------------------------------------------------
*/

    .begin      literal_prefix .NMIExceptionVector
    .section    .NMIExceptionVector.text, "ax"
    .global     NMIExceptionVector
    .type       NMIExceptionVector,@function
    .align      4

NMIExceptionVector:
    j   _xt_unhandled_exc

    .end        literal_prefix

/*
--------------------------------------------------------------------------------
Kernel Exception
--------------------------------------------------------------------------------
*/

    .begin      literal_prefix .KernelExceptionVector
    .section    .KernelExceptionVector.text, "ax"
    .global     KernelExceptionVector
    .type       KernelExceptionVector,@function
    .align      4

KernelExceptionVector:
    j   _xt_unhandled_exc

    .end        literal_prefix

/*
--------------------------------------------------------------------------------
User Exception
--------------------------------------------------------------------------------
*/

    .begin      literal_prefix .UserExceptionVector
    .section    .UserExceptionVector.text, "ax"
    .global     _UserExceptionVector
    .type       _UserExceptionVector,@function
    .align      4

_UserExceptionVector:

    wsr     a0, EXCSAVE1                   /* preserve a0 */
    j   _xt_user_exc                    /* user exception handler */
    /* never returns here - call0 is used as a jump (see note at top) */

    .end        literal_prefix

/*
--------------------------------------------------------------------------------
Double Exception
--------------------------------------------------------------------------------
*/

    .begin      literal_prefix .DoubleExceptionVector
    .section    .DoubleExceptionVector.text, "ax"
    .global     DoubleExceptionVector
    .type       DoubleExceptionVector,@function
    .align      4

DoubleExceptionVector:
    j   _xt_unhandled_exc

    .end        literal_prefix
