/******************************************************************************
 * $Revision: 423 $
 * $Date:: 2017-04-07 16:03:30 +0900#$
 *****************************************************************************/
/* __DISCLAIMER_START__                                                      */
/******************************************************************************
* (c)2017, Cypress Semiconductor Corporation
* or a subsidiary of Cypress Semiconductor Corporation. All rights
* reserved.
*
* This software, including source code, documentation and related
* materials ( "Software" ), is owned by Cypress Semiconductor
* Corporation or one of its subsidiaries ( "Cypress" ) and is protected by
* and subject to worldwide patent protection (United States and foreign),
* United States copyright laws and international treaty provisions.
* Therefore, you may use this Software only as provided in the license
* agreement accompanying the software package from which you
* obtained this Software ( "EULA" ).
*
* If no EULA applies, Cypress hereby grants you a personal, nonexclusive,
* non-transferable license to copy, modify, and compile the
* Software source code solely for use in connection with Cypress' s
* integrated circuit products. Any reproduction, modification, translation,
* compilation, or representation of this Software except as specified
* above is prohibited without the express written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO
* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING,
* BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. Cypress reserves the right to make
* changes to the Software without notice. Cypress does not assume any
* liability arising out of the application or use of the Software or any
* product or circuit described in the Software. Cypress does not
* authorize its products for use in any products where a malfunction or
* failure of the Cypress product may reasonably be expected to result in
* significant property damage, injury or death ( "High Risk Product" ). By
* including Cypress' s product in a High Risk Product, the manufacturer
* of such system or application assumes all risk of such use and in doing
* so agrees to indemnify Cypress against all liability.
******************************************************************************/
/* __DISCLAIMER_END__                                                        */
/*****************************************************************************/
/** \file exceptions.c
 **
 ** Definition of exception vectors initialization function and default
 ** exception handlers. The assignment of exception vectors must be done in
 ** exceptions.h.
 **
 ** \note Setting the exception vectors will only work if the high-boot
 **       option is enabled for the R5F core (HIVECS == 1, see ARM TRM). This
 **       means, the exception table is located at 0xFFFF0000, inside the
 **       build-in BootROM.
 **
 ** History:
 **   - 2015-09-01  0.01  HS  Initial version for Traveo
 *****************************************************************************/

// File version 0xYYXX = vYY.XX
#define EXCEPTIONS_C_VERSION          0x0001

#ifndef __FILE_VERSION_CHECK__

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#include "exceptions.h"
#include "mcu_settings.h"
#include "abstract.h"
//
/*****************************************************************************/
/* Local pre-processor symbols/macros ('#define')                            */
/*****************************************************************************/

/** Key to unlock the BootROM Hardware Interface by writing to EXCFG_UNLOCK register */
#define BOOTROM_KEY_UNLOCK      0xACC5B007 
/** Key to lock the BootROM Hardware Interface by writing to EXCFG_UNLOCK register */
#define BOOTROM_KEY_LOCK        0xB007ECF6

/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/

/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/

/*****************************************************************************/
/* Local function prototypes ('static')                                      */
/*****************************************************************************/
static void DefaultUndefinedInstructionExceptionHandler(void);
static void DefaultSupervisorCallExceptionHandler(void);
static void DefaultPrefetchAbortExceptionHandler(void);
void DefaultDataAbortExceptionIsr(void);
void DefaultDataAbortExceptionHandler(void);

/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/
/// Callback function pointer for the Supervisor Call (defined in exceptions.h)
static const svc_hdl_func_ptr_t m_pfnSupervisorCallHandlerCallback = EXCEPTIONS_SVC_HANDLER_CB ;


/*****************************************************************************/
/* Function implementation - global ('extern') and local ('static')          */
/*****************************************************************************/

/**
 ******************************************************************************
 ** \brief Initialize the BootROM Hardware Interface
 **
 ** This function will re-map the exception vectors of the ARM exception table
 ** inside the BootROM to the handlers which are defined in exceptions.h.
 ** During this operation the BootROM Hardware Interface will be unlocked
 ** to enable write access to the exception vector configuration registers.
 ** Before leaving this function, the new exception vector configuration will be
 ** swapped with the current configuration.
 **
 ** \note Setting the exception vectors will only work if the high-boot
 **       option is enabled for the R5F core (HIVECS == 1, see ARM TRM). This
 **       means, the exception table is located at 0xFFFF0000, inside the
 **       build-in BootROM.
 **
 ** \pre Must be in system mode
 **
 ******************************************************************************/
void Exceptions_Init(void)
{
    // Unlock BootROM Hardware Interface registers
    EXCFG_UNLOCK = BOOTROM_KEY_UNLOCK;
    
    // Set exception vector registers in inactive configuration set
    EXCFG_UNDEFINACT  = (uint32_t)EXCEPTIONS_EXC_HANDLER_UNDEF_INSTR;     // Undefined instruction handler
    EXCFG_SVCINACT    = (uint32_t)EXCEPTIONS_EXC_HANDLER_SVC;             // Supervisor call handler
    EXCFG_PABORTINACT = (uint32_t)EXCEPTIONS_EXC_HANDLER_PABORT;          // Prefetch abort handler
    EXCFG_DABORTINACT = (uint32_t)EXCEPTIONS_EXC_HANDLER_DABORT;          // Data abort handler
    // Note: EXCFG_IRQINACT for interrupt exception vector
    //       is not available
    // Note: EXCFG_NMIINACT for Non-maskable interrupt exception vector
    //       is not available due to Interrupt Controller providing
    //       the NMI (FIQ) vector at NMIVAS mirror register below BootROM

    // Swap inactive <-> active exception vector configuration sets
    EXCFG_CNFG_SWAP = 1;
    
    // Finally lock BootROM Hardware Interface registers
    EXCFG_UNLOCK = BOOTROM_KEY_LOCK;
}

/**
 ******************************************************************************
 ** \brief Default handler for Undefined Instruction Exception
 **
 ** ARM Cortex-R5(F) TRM: "When an instruction is encountered which is UNDEFINED,
 ** or is for the VFP when the VFP is not enabled, the processor takes the Undefined
 ** instruction exception. Software can use this mechanism to extend the ARM
 ** instruction set by emulating UNDEFINED coprocessor instructions. UNDEFINED
 ** exceptions also occur when a UDIV  or SDIV instruction is executed, the value
 ** in Rm is zero, and the DZ bit in the System Control Register is set."
 **
 ** If the handler is required to return after the instruction that caused the
 ** Undefined exception, please refer to the ARM Cortex-R5(F) TRM.
 **
 ** \todo add full implementation
 ******************************************************************************/
static void DefaultUndefinedInstructionExceptionHandler(void)
{
    // IRQs are disabled now.
    // Please refer to the ARM documentation on how to handle this exception.
    while (1)
    {
        NOP();
    }
}

/**
 ******************************************************************************
 ** \brief Default handler for Supervisor Call Execution
 **
 ** This function is an internal wrapper and is called by the real SVC handler
 ** The callback function is user defined in exceptions.h and can be used to
 ** execute code in privileged mode.
 **
 ** \param u32ServiceNumber Number of SVC provided by the handler
 **
 ******************************************************************************/
// GCC does not yet support switching instruction set by source file statements
#ifdef __TOOLCHAIN_GCC__
    #ifdef __thumb__
        #warning "File must not be compiled with Thumb instruction set!"
    #endif
#endif
 
#ifdef __TOOLCHAIN_IAR__
    __arm void SupervisorCallHandler( uint32_t u32ServiceNumber );
    __arm
#elif defined __TOOLCHAIN_GHS_MULTI__
    #if defined(__THUMB_AWARE__) && defined(__THUMB__)   
        # pragma ghs nothumb   
    #endif /* defined(__THUMB_AWARE__) && defined(__THUMB__) */   
#endif
void SupervisorCallHandler( uint32_t u32ServiceNumber )
{
    if ( m_pfnSupervisorCallHandlerCallback != NULL )
    {
        m_pfnSupervisorCallHandlerCallback( u32ServiceNumber ) ;
    }
} // SupervisorCallHandler
#if defined __TOOLCHAIN_GHS_MULTI__
    #if defined(__THUMB_AWARE__) && defined(__THUMB__)   
        # pragma ghs thumb   
    #endif /* defined(__THUMB_AWARE__) && defined(__THUMB__) */   
#endif

/**
 ******************************************************************************
 ** \brief Default handler for Supervisor Call Exception
 **
 ** ARM Cortex-R5(F) TRM: "You can use the SuperVisor Call (SVC) instruction
 ** (formerly SWI) to enter Supervisor mode, usually to request a particular
 ** supervisor function. The SVC handler reads the opcode to extract the SVC
 ** function number. A SVC handler returns by executing the following instruction,
 ** irrespective of the processor operating state: MOVS PC, R14_svc
 ** This action restores the PC and CPSR, and returns to the instruction following
 ** the SVC."
 **
 ******************************************************************************/
#ifdef __TOOLCHAIN_IAR__
    #pragma required=SupervisorCallHandler
    __arm
#elif defined __TOOLCHAIN_GHS_MULTI__
    #if defined(__THUMB_AWARE__) && defined(__THUMB__)   
        # pragma ghs nothumb   
    #endif /* defined(__THUMB_AWARE__) && defined(__THUMB__) */   
#endif
static void DefaultSupervisorCallExceptionHandler(void)
{
    ASM_INLINE( "STMFD   sp!, {r0-r12, r14}    " ) ; // Store registers
    ASM_INLINE( "MOV     r1, sp                " ) ; // Set pointer to parameters
    ASM_INLINE( "MRS     r0, spsr              " ) ; // Move SPSR into general purpose register
    ASM_INLINE( "TST     r0, #0x20             " ) ; // Test if bit 5 is set (THUMB mode)
    ASM_INLINE( "LDRNEH  r0, [lr, #-2]         " ) ; // T_bit set so load halfword (Thumb)
    ASM_INLINE( "BICNE   r0, r0, #0xFF00       " ) ; //  and clear top 8 bits of halfword
    ASM_INLINE( "LDREQ   r0, [lr, #-4]         " ) ; // T_bit clear so load word (ARM)
    ASM_INLINE( "BICEQ   r0, r0, #0xFF000000   " ) ; //  and clear top 8 bits of word

    // r0 now contains SVC number
    // r1 now contains pointer to stacked registers
    ASM_INLINE( "BL      SupervisorCallHandler       " ) ; // Call main SVC handler

    ASM_INLINE( "LDMFD   sp!, {r0-r12, r14}    " ) ; // Restore registers and return
    ASM_INLINE( "MOVS    PC, R14               " ) ; // Return from SVC exception (no re-execution, next instruction)

    // ToDo reenable IRQs
} // DefaultSupervisorCallExceptionHandler
#if defined __TOOLCHAIN_GHS_MULTI__
    #if defined(__THUMB_AWARE__) && defined(__THUMB__)   
        # pragma ghs thumb   
    #endif /* defined(__THUMB_AWARE__) && defined(__THUMB__) */   
#endif

/**
 ******************************************************************************
 ** \brief Default handler for Prefetch Abort Exception
 **
 ** ARM Cortex-R5(F) TRM: "When the processor's memory system cannot complete
 ** a memory access successfully, an abort is generated. Aborts can occur for
 ** a number of reasons, for example:
 **     - a permission fault indicated by the MPU
 **     - an error response to a transaction on the AXI memory bus
 **     - an error detected in the data by the ECC checking logic.
 ** An error occurring on an instruction fetch generates a prefetch abort.
 ** When a Prefetch Abort (PABT) occurs, the processor marks the prefetched
 ** instruction as invalid, but does not take the exception until the instruction
 ** is to be executed. If the instruction is not executed, for example because
 ** a branch occurs while it is in the pipeline, the abort does not take place.
 ** All prefetch aborts are precise."
 **
 ** \todo add full implementation
 ******************************************************************************/
static void DefaultPrefetchAbortExceptionHandler(void)
{
    // IRQs are disabled now.
    // Please refer to the ARM documentation on how to handle this exception.

    // For debugging purpose only
    #ifdef DEBUG
    // Collect some information about the cause of the prefetch abort
    volatile uint32_t u32InstructionFaultStatus    = MRC( 15, 0,  5, 0, 1 );
    volatile uint32_t u32AuxInstructionFaultStatus = MRC( 15, 0,  5, 1, 1 );
    volatile uint32_t u32InstructionFaultAddress   = MRC( 15, 0,  6, 0, 2 );
    #endif // DEBUG

    while (1)
    {
        NOP();
    }
}
/**
 ******************************************************************************
 ** \brief Default handler for Prefetch Abort Exception
 **
 ** ARM Cortex-R5(F) TRM: "When the processor's memory system cannot complete
 ** a memory access successfully, an abort is generated. Aborts can occur for
 ** a number of reasons, for example:
 **     - a permission fault indicated by the MPU
 **     - an error response to a transaction on the AXI memory bus
 **     - an error detected in the data by the ECC checking logic.
 ** An error occurring on a data memory access can generate a data abort. [...]
 ** A Data Abort (DABT) can be either precise or imprecise, depending on the type
 ** of fault that caused it."
 **
 ** \todo add full implementation
 ******************************************************************************/
void DefaultDataAbortExceptionIsr(void)
{
    // IRQs are disabled now.
    // Please refer to the ARM documentation on how to handle this exception.

    // For debugging purpose only
    #ifdef DEBUG
    // Collect some information about the cause of the data abort
    volatile uint32_t u32DataFaultStatus    = MRC( 15, 0,  5, 0, 0 );
    volatile uint32_t u32AuxDataFaultStatus = MRC( 15, 0,  5, 1, 0 );
    volatile uint32_t u32DataFaultAddress   = MRC( 15, 0,  6, 0, 0 );
    #endif // DEBUG

    /*  DLP Error Fault flag is cleared for calibration of DLP.*/
    if(DDRHSSPI0_FAULTF_DLPFS)
    {
        DDRHSSPI0_FAULTC_DLPFC = 0x1;  /*DLP Error Fault Clear*/
    }
    else if(DDRHSSPI0_FAULTF_DRCBSFS)
    {
        DDRHSSPI0_FAULTC_DRCBSFC = 0x1; /*DMA Read Channel Block Size Fault Status Clear*/
    }
    else if(DDRHSSPI0_FAULTF_PVFS)
    {
        DDRHSSPI0_FAULTC_PVFC = 0x1; /*Protection Violation Fault Status Clear*/
    }
    else if(DDRHSSPI0_FAULTF_DWCBSFS)
    {
        DDRHSSPI0_FAULTC_DWCBSFC = 0x1; /*DMA Write Channel Block Size Fault Status Clear*/
    }
    else if(DDRHSSPI0_FAULTF_UMAFS)
    {
        DDRHSSPI0_FAULTC_UMAFC = 0x1; /*Unmapped Memory Access Fault Interrupt Clear*/
    }
    else
    {
         while (1)
         {
            NOP();
         }
    }
}

#endif /* __FILE_VERSION_CHECK__ */

