/*
    ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio.

    This file is part of ChibiOS.

    ChibiOS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    ChibiOS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @file    ivor.s
 * @brief   Kernel ISRs.
 *
 * @addtogroup PPC_CORE
 * @{
 */

#if !defined(FALSE) || defined(__DOXYGEN__)
#define FALSE   0
#endif

#if !defined(TRUE) || defined(__DOXYGEN__)
#define TRUE    1
#endif

/*
 * Imports the PPC configuration headers.
 */
#define _FROM_ASM_
#include "chlicense.h"
#include "chconf.h"
#include "chcore.h"

#if !defined(__DOXYGEN__)

        .section    .handlers, "ax"

#if PPC_SUPPORTS_DECREMENTER
        /*
         * _IVOR10 handler (Book-E decrementer).
         */
        .align      4
        .globl      _IVOR10
        .type       _IVOR10, @function
_IVOR10:
        /* Saving the external context (port_extctx structure).*/
        stwu        %sp, -80(%sp)
#if PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI
        e_stmvsrrw  8(%sp)                  /* Saves PC, MSR.               */
        e_stmvsprw  16(%sp)                 /* Saves CR, LR, CTR, XER.      */
        e_stmvgprw  32(%sp)                 /* Saves GPR0, GPR3...GPR12.    */
#else /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
        stw         %r0, 32(%sp)            /* Saves GPR0.                  */
        mfSRR0      %r0
        stw         %r0, 8(%sp)             /* Saves PC.                    */
        mfSRR1      %r0
        stw         %r0, 12(%sp)            /* Saves MSR.                   */
        mfCR        %r0
        stw         %r0, 16(%sp)            /* Saves CR.                    */
        mfLR        %r0
        stw         %r0, 20(%sp)            /* Saves LR.                    */
        mfCTR       %r0
        stw         %r0, 24(%sp)            /* Saves CTR.                   */
        mfXER       %r0
        stw         %r0, 28(%sp)            /* Saves XER.                   */
        stw         %r3, 36(%sp)            /* Saves GPR3...GPR12.          */
        stw         %r4, 40(%sp)
        stw         %r5, 44(%sp)
        stw         %r6, 48(%sp)
        stw         %r7, 52(%sp)
        stw         %r8, 56(%sp)
        stw         %r9, 60(%sp)
        stw         %r10, 64(%sp)
        stw         %r11, 68(%sp)
        stw         %r12, 72(%sp)
#endif /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */

        /* Increasing the SPGR0 register.*/
        mfspr       %r0, 272
        eaddi       %r0, %r0, 1
        mtspr       272, %r0

        /* Reset DIE bit in TSR register.*/
        lis         %r3, 0x0800             /* DIS bit mask.                */
        mtspr       336, %r3                /* TSR register.                */

        /* Restoring pre-IRQ MSR register value.*/
        mfSRR1      %r0
#if !PPC_USE_IRQ_PREEMPTION
        /* No preemption, keeping EE disabled.*/
        se_bclri    %r0, 16                 /* EE = bit 16.                 */
#endif
        mtMSR       %r0

#if CH_DBG_SYSTEM_STATE_CHECK
        bl          _dbg_check_enter_isr
        bl          _dbg_check_lock_from_isr
#endif
        /* System tick handler invocation.*/
        bl          chSysTimerHandlerI
#if CH_DBG_SYSTEM_STATE_CHECK
        bl          _dbg_check_unlock_from_isr
        bl          _dbg_check_leave_isr
#endif

#if PPC_USE_IRQ_PREEMPTION
        /* Prevents preemption again.*/
        wrteei      0
#endif

        /* Jumps to the common IVOR epilogue code.*/
        b           _ivor_exit
#endif /* PPC_SUPPORTS_DECREMENTER */

        /*
         * _IVOR4 handler (Book-E external interrupt).
         */
        .align      4
        .globl      _IVOR4
        .type       _IVOR4, @function
_IVOR4:
        /* Saving the external context (port_extctx structure).*/
        stwu        %sp, -80(%sp)
#if PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI
        e_stmvsrrw  8(%sp)                  /* Saves PC, MSR.               */
        e_stmvsprw  16(%sp)                 /* Saves CR, LR, CTR, XER.      */
        e_stmvgprw  32(%sp)                 /* Saves GPR0, GPR3...GPR12.    */
#else /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
        stw         %r0, 32(%sp)            /* Saves GPR0.                  */
        mfSRR0      %r0
        stw         %r0, 8(%sp)             /* Saves PC.                    */
        mfSRR1      %r0
        stw         %r0, 12(%sp)            /* Saves MSR.                   */
        mfCR        %r0
        stw         %r0, 16(%sp)            /* Saves CR.                    */
        mfLR        %r0
        stw         %r0, 20(%sp)            /* Saves LR.                    */
        mfCTR       %r0
        stw         %r0, 24(%sp)            /* Saves CTR.                   */
        mfXER       %r0
        stw         %r0, 28(%sp)            /* Saves XER.                   */
        stw         %r3, 36(%sp)            /* Saves GPR3...GPR12.          */
        stw         %r4, 40(%sp)
        stw         %r5, 44(%sp)
        stw         %r6, 48(%sp)
        stw         %r7, 52(%sp)
        stw         %r8, 56(%sp)
        stw         %r9, 60(%sp)
        stw         %r10, 64(%sp)
        stw         %r11, 68(%sp)
        stw         %r12, 72(%sp)
#endif /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */

        /* Increasing the SPGR0 register.*/
        mfspr       %r0, 272
        eaddi       %r0, %r0, 1
        mtspr       272, %r0

        /* Software vector address from the INTC register.*/
        lis         %r3, INTC_IACKR_ADDR@h
        ori         %r3, %r3, INTC_IACKR_ADDR@l /* IACKR register address.  */
        lwz         %r3, 0(%r3)             /* IACKR register value.        */
        lwz         %r3, 0(%r3)
        mtCTR       %r3                     /* Software handler address.    */

        /* Restoring pre-IRQ MSR register value.*/
        mfSRR1      %r0
#if !PPC_USE_IRQ_PREEMPTION
        /* No preemption, keeping EE disabled.*/
        se_bclri    %r0, 16                 /* EE = bit 16.                 */
#endif
        mtMSR       %r0

        /* Exectes the software handler.*/
        bctrl

#if PPC_USE_IRQ_PREEMPTION
        /* Prevents preemption again.*/
        wrteei      0
#endif

        /* Informs the INTC that the interrupt has been served.*/
        mbar        0
        lis         %r3, INTC_EOIR_ADDR@h
        ori         %r3, %r3, INTC_EOIR_ADDR@l
        stw         %r3, 0(%r3)             /* Writing any value should do. */

        /* Common IVOR epilogue code, context restore.*/
        .globl      _ivor_exit
_ivor_exit:
        /* Decreasing the SPGR0 register.*/
        mfspr       %r0, 272
        eaddi       %r0, %r0, -1
        mtspr       272, %r0

#if CH_DBG_STATISTICS
        bl          _stats_start_measure_crit_thd
#endif
#if CH_DBG_SYSTEM_STATE_CHECK
        bl          _dbg_check_lock
#endif
        bl          chSchIsPreemptionRequired
        cmpli       cr0, %r3, 0
        beq         cr0, .noresch
        bl          chSchDoReschedule
.noresch:
#if CH_DBG_SYSTEM_STATE_CHECK
        bl          _dbg_check_unlock
#endif
#if CH_DBG_STATISTICS
        bl          _stats_stop_measure_crit_thd
#endif

        /* Restoring the external context.*/
#if PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI
        e_lmvgprw   32(%sp)                 /* Restores GPR0, GPR3...GPR12. */
        e_lmvsprw   16(%sp)                 /* Restores CR, LR, CTR, XER.   */
        e_lmvsrrw   8(%sp)                  /* Restores PC, MSR.            */
#else /*!(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
        lwz         %r3, 36(%sp)            /* Restores GPR3...GPR12.       */
        lwz         %r4, 40(%sp)
        lwz         %r5, 44(%sp)
        lwz         %r6, 48(%sp)
        lwz         %r7, 52(%sp)
        lwz         %r8, 56(%sp)
        lwz         %r9, 60(%sp)
        lwz         %r10, 64(%sp)
        lwz         %r11, 68(%sp)
        lwz         %r12, 72(%sp)
        lwz         %r0, 8(%sp)
        mtSRR0      %r0                     /* Restores PC.                 */
        lwz         %r0, 12(%sp)
        mtSRR1      %r0                     /* Restores MSR.                */
        lwz         %r0, 16(%sp)
        mtCR        %r0                     /* Restores CR.                 */
        lwz         %r0, 20(%sp)
        mtLR        %r0                     /* Restores LR.                 */
        lwz         %r0, 24(%sp)
        mtCTR       %r0                     /* Restores CTR.                */
        lwz         %r0, 28(%sp)
        mtXER       %r0                     /* Restores XER.                */
        lwz         %r0, 32(%sp)            /* Restores GPR0.               */
#endif /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
        addi        %sp, %sp, 80            /* Back to the previous frame.  */
        rfi

#endif /* !defined(__DOXYGEN__) */

/** @} */
