/******************************************************************************
 * $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 abstract.h
 **
 ** Toolchain/Compiler abstraction. Assignment of build-in functions and macros.
 **
 ** History:
 **   - 2015-09-01  0.01  HS  Initial version for Traveo
 *****************************************************************************/

#ifndef __ABSTRACT_H__
#define __ABSTRACT_H__

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

#ifndef __FILE_VERSION_CHECK__


#ifdef __ICCARM__
    #define __TOOLCHAIN_IAR__
#endif

#ifdef __ghs__
    #define __TOOLCHAIN_GHS_MULTI__
#endif

#ifdef __GNUC__
    #define __TOOLCHAIN_GCC__
#endif

/*****************************************************************************/
/* Include files                                                             */
/*****************************************************************************/
#ifdef __TOOLCHAIN_IAR__
    #include <intrinsics.h> // IAR intrinsic functions (e.g. __enable_interrupt())
#endif

#ifdef __TOOLCHAIN_GHS_MULTI__
    #include <arm_ghs.h>   // GHS MULTI intrinsic functions (e.g. __enable_interrupt())
#endif

#ifdef __TOOLCHAIN_GCC__
    // no header for intrinsic functions
#endif

/*****************************************************************************/
/* Global pre-processor symbols/macros ('#define')                           */
/*****************************************************************************/

#ifdef __TOOLCHAIN_IAR__

    /** Keyword for a function call using an SWI */
    #define SWI_NR_PRAGMA(arg) _Pragma(#arg)
    #define SWI_CALL(nr,intfn) SWI_NR_PRAGMA(swi_number=nr)     __swi void intfn (void)

    /** Macro to insert a No Operation instruction */
    #define NOP()               __no_operation()
    /** Macro to insert a Data Synchronization Barrier instruction */
    #define DSB()               __DSB()
    /** Macro to insert an Instruction Synchronization Barrier instruction */
    #define ISB()               __ISB()
    /** Macro to insert a Data Memory Barrier instruction */
    #define DMB()               __DMB()
    /** Macro to insert a CLZ instruction (returns leading zeros of a 32-bit value, started at bit31) */
    #define CLZ(u32Value)       __CLZ(u32Value)
    
    /** Macro to write the CPSR register */
    #define SET_CPSR(u32Value)  __set_CPSR(u32Value) ;
    /** Macro to read the CPSR register */
    #define GET_CPSR()          __get_CPSR() ;

    /** Macro for inline assembly */
    #define ASM_INLINE(instr)   __asm volatile(instr)
            
    /** Macro to insert a coprocessor read instruction (MRC).
     ** Returns a 32-bit value from the co-processor. */
    #define MRC(u32CoPrc, u32OpCode1, u32CRn, u32CRm, u32OpCode2)  \
                                    __MRC(u32CoPrc, u32OpCode1, u32CRn, u32CRm, u32OpCode2)
    /** Macro to insert a coprocessor write instruction (MCR).
     ** Passes a 32-bit value (u32Rd) to the co-processor. */
    #define MCR(u32CoPrc, u32OpCode1, u32Rd, u32CRn, u32CRm, u32OpCode2)  \
                                    __MCR(u32CoPrc, u32OpCode1, u32Rd, u32CRn, u32CRm, u32OpCode2)  \

    // -------------------------------------------------------------------
    // M A C R O S   F O R   I N T E R R U P T S   ( I R Q )
    // -------------------------------------------------------------------

    /** Macro to disable IRQs. This will set the i-flag in the CPSR to mask further IRQs. */
    #define IRQ_DISABLE()           ASM_INLINE("CPSID I")
    /** Macro to enable IRQs. This will clear the i-flag in the CPSR to accept IRQs. */
    #define IRQ_ENABLE()            ASM_INLINE("CPSIE I")

    /** Macro to disable IRQs. This will set the I-flag in the CPSR to mask further IRQs.*/
    /** This macro must be used in  a same block with IRQ_RESTORE() . */
    #define IRQ_DISABLE_LOCAL()     {\
                                        __istate_t interrupt_state;\
                                        interrupt_state = __get_interrupt_state();\
                                        __disable_irq();

    /** Macro to enable IRQs. This will set the I-flag in the CPSR to accept IRQs.*/
    /** This macro must be used in  a same block with IRQ_RESTORE() . */
    #define IRQ_ENABLE_LOCAL()      {\
                                        __istate_t interrupt_state;\
                                        interrupt_state = __get_interrupt_state();\
                                        __enable_irq();

    /** Macro to restore IRQ state. This will restore the I-flag */
    /** This macro must be used in  a same block with IRQ_DISABLE_LOCAL() or IRQ_ENABLE_LOCAL(). */
    #define IRQ_RESTORE()               __set_interrupt_state(interrupt_state);\
                                    }

    /** Macro to enable NMIs. This will clear the f-flag in the CPSR to accept NMIs (FIQ).
     ** After reset, NMIs can be enabled. After this, it is not possible to disable/mask them again,
     ** except by entering forcing a NMI to enter FIQ mode. */
    #define NMI_ENABLE()            ASM_INLINE("CPSIE F")
   
    /** Macro containing the keywords to mark a function as interrupt
     ** service routine (ISR) for IRQs supporting interrupt nesting.
     ** This will signal the compiler to create the required assembler
     ** entry and exit code for an IRQ handler supporting nested
     ** interrupts i.e. during execution of the ISR interrupts with
     ** higher priority level can interrupt the ISR.*/
    #define FN_IRQ_NESTED           __irq __arm __nested
        
    /** Macro containing the keywords to mark a function as interrupt
     ** service routine (ISR) for IRQs. This will signal the compiler
     ** to create the required assembler entry and exit code for
     ** an IRQ handler. During ISR execution, no other interrupts
     ** will be accepted. */
    #define FN_IRQ_NOT_NESTED       __irq __arm
            
    // -------------------------------------------------------------------------------
    // M A C R O S   F O R   N O N - M A S K A B L E   I N T E R R U P T S   ( N M I )
    // -------------------------------------------------------------------------------

    /** Keyword for a NMI handler function definition */
    #define FN_NMI                  __fiq __arm
    
#endif

#ifdef __TOOLCHAIN_GHS_MULTI__

    /** Keyword for a function call using an SWI */
    #define SWI_CALL( nr, name ) __swi( nr ) void name(void) 
    
    /** Macro to insert a No Operation instruction */
    #define NOP()               __asm("NOP")
    /** Macro to insert a Data Synchronization Barrier instruction */
    #define DSB()               __asm("DSB")
    /** Macro to insert an Instruction Synchronization Barrier instruction */
    #define ISB()               __asm("ISB")
    /** Macro to insert a Data Memory Barrier instruction */
    #define DMB()               __asm("DMB")
    /** Macro to insert a CLZ instruction (returns leading zeros of a 32-bit value, started at bit31) */
    #define CLZ(u32Value)       __CLZ32(u32Value)

    /** Macro to write the CPSR register */
    #define SET_CPSR(u32Value)  __SETSR(u32Value) ;
    /** Macro to read the CPSR register */
    #define GET_CPSR()          __GETSR() ;

    /** Macro for inline assembly */
    #define ASM_INLINE(instr)   __asm(instr)
    
    /** Macro to insert a coprocessor read instruction (MRC).
     ** Returns a 32-bit value from the co-processor. */
    #define MRC(u32CoPrc, u32OpCode1, u32CRn, u32CRm, u32OpCode2)  \
                                    __MRC(u32CoPrc, u32OpCode1, u32CRn, u32CRm, u32OpCode2)
    /** Macro to insert a coprocessor write instruction (MCR).
     ** Passes a 32-bit value (u32Rd) to the co-processor. */
    #define MCR(u32CoPrc, u32OpCode1, u32Rd, u32CRn, u32CRm, u32OpCode2)  \
                                    __MCR(u32CoPrc, u32OpCode1, u32Rd, u32CRn, u32CRm, u32OpCode2)  \

    // -------------------------------------------------------------------
    // M A C R O S   F O R   I N T E R R U P T S   ( I R Q )
    // -------------------------------------------------------------------

    /** Macro to disable IRQs. This will set the i-flag in the CPSR to mask further IRQs. */
    #define IRQ_DISABLE()           ASM_INLINE("CPSID I")
    /** Macro to enable IRQs. This will clear the i-flag in the CPSR to accept IRQs. */
    #define IRQ_ENABLE()            ASM_INLINE("CPSIE I")
    
    /** Macro to disable IRQs. This will set the I-flag in the CPSR to mask further IRQs.*/
    /** This code also try to set the F-flag, but it is not possible to set the F-flag again */
    /** after the F-flag is cleared. So, setting the F-flag will be ignored. */
    /** This macro must be used in  a same block with IRQ_RESTORE(), */
    /** and be only used after the F-flag is cleared. */
    #define IRQ_DISABLE_LOCAL()     {\
                                        unsigned int interrupt_state;\
                                        interrupt_state = __DIR();

    /** Macro to enable IRQs. This will set the I-flag in the CPSR to accept IRQs.*/
    /** This macro must be used in  a same block with IRQ_RESTORE(), */
    /** and be only used after the F-flag is cleared. */
    #define IRQ_ENABLE_LOCAL()      {\
                                        unsigned int interrupt_state;\
                                        interrupt_state = __EIR();

    /** Macro to restore IRQ state. This will restore the I-flag */
    #define IRQ_RESTORE()               __RIR(interrupt_state);\
                                    }

    /** Macro to enable NMIs. This will clear the f-flag in the CPSR to accept NMIs (FIQ).
     ** After reset, NMIs can be enabled. After this, it is not possible to disable/mask them again,
     ** except by entering forcing a NMI to enter FIQ mode. */
    #define NMI_ENABLE()            ASM_INLINE("CPSIE F")
    
    /** Macro containing the keywords to mark a function as interrupt
     ** service routine (ISR) for IRQs supporting interrupt nesting.
     ** This will signal the compiler to create the required assembler
     ** entry and exit code for an IRQ handler supporting nested
     ** interrupts i.e. during execution of the ISR interrupts with
     ** higher priority level can interrupt the ISR.*/
    //#define FN_IRQ_NESTED          __interrupt
    // Currently interrupt nesting is not supported by GHS compiler
           
    /** Macro containing the keywords to mark a function as interrupt
     ** service routine (ISR) for IRQs. This will signal the compiler
     ** to create the required assembler entry and exit code for
     ** an IRQ handler. During ISR execution, no other interrupts
     ** will be accepted.
     ** GHS compiler will automatically compile __interrupt functions in ARM  mode. */
    #define FN_IRQ_NOT_NESTED       __interrupt

    // -------------------------------------------------------------------------------
    // M A C R O S   F O R   N O N - M A S K A B L E   I N T E R R U P T S   ( N M I )
    // -------------------------------------------------------------------------------

    /** Keyword for a NMI handler function definition */
    #define FN_NMI                  __interrupt 

#endif


#ifdef __TOOLCHAIN_GCC__	

    /** Keyword for a function call using an SWI */
    #define SWI_CALL( nr, name ) __attribute__ ((interrupt ("SWI"))) void name(void) 
    
    /** Macro to insert a No Operation instruction */
    #define NOP()               __asm__ __volatile__ ("nop")
    /** Macro to insert a Data Synchronization Barrier instruction */
    #define DSB()               __asm__ __volatile__ ("dsb" : : : "memory")
    /** Macro to insert a Data Memory Barrier instruction */
    #define DMB()               __asm__ __volatile__ ("dmb" : : : "memory")
    /** Macro to insert an Instruction Synchronization Barrier instruction */
    #define ISB()               __asm__ __volatile__ ("isb" : : : "memory")
    /** Macro to insert a CLZ instruction (returns leading zeros of a 32-bit value, started at bit31) */
    #define CLZ(u32Value)        __builtin_clzl(u32Value)

    /** Macro to write the CPSR register */
    #define SET_CPSR(u32Value)  __asm__ __volatile__ ("msr cpsr_cxsf, %[reg]" : : [reg] "r" (u32Value) : "cc")
    /** Macro to read the CPSR register */
    #define GET_CPSR()            \
            ({ \
                volatile unsigned long __reg_content; \
                __asm__ __volatile__ ("mrs %[reg], cpsr" : [reg] "=r" (__reg_content) : : ); \
                __reg_content; \
            })

    /** Macro for inline assembly */
    #define ASM_INLINE(instr)   __asm__ __volatile__ (instr)

     
    /** Only required in MRC() / MCR() macros.
     ** Expands a string containing the actual assembler MRC/MCR instruction requested by the user. (e.g. "mcr p15, 0, %[reg], c5, c0, 0") */
    #define __MRCMCR_STRING(mrcmcr, u32CoPrc, u32OpCode1, u32CRn, u32CRm, u32OpCode2)  \
            mrcmcr " p" #u32CoPrc ", " #u32OpCode1 ", %[reg], c" #u32CRn ", c" #u32CRm ", " #u32OpCode2

    /** Macro to insert a coprocessor read instruction (MRC).
     ** Returns a 32-bit value from the co-processor. */
    #define MRC(u32CoPrc, u32OpCode1, u32CRn, u32CRm, u32OpCode2)  \
            ({ \
                volatile unsigned long __reg_content; \
                __asm__ __volatile__ (__MRCMCR_STRING("mrc", u32CoPrc, u32OpCode1, u32CRn, u32CRm, u32OpCode2) : [reg] "=r" (__reg_content) : : ); \
                __reg_content; \
            })
    
    /** Macro to insert a coprocessor write instruction (MCR).
     ** Passes a 32-bit value (u32Rd) to the co-processor. */
    #define MCR(u32CoPrc, u32OpCode1, u32Rd, u32CRn, u32CRm, u32OpCode2)  \
            __asm__ __volatile__ (__MRCMCR_STRING("mcr", u32CoPrc, u32OpCode1, u32CRn, u32CRm, u32OpCode2) : : [reg] "r" (u32Rd) : )


    // -------------------------------------------------------------------
    // M A C R O S   F O R   I N T E R R U P T S   ( I R Q )
    // -------------------------------------------------------------------

    /** Macro to disable IRQs. This will set the i-flag in the CPSR to mask further IRQs. */
    #define IRQ_DISABLE()           __asm__ __volatile__ ("cpsid i")
    /** Macro to enable IRQs. This will clear the i-flag in the CPSR to accept IRQs. */
    #define IRQ_ENABLE()            __asm__ __volatile__ ("cpsie i")
    
    /** Macro to disable IRQs. This will set the I-flag in the CPSR to mask further IRQs.*/
    /** This macro must be used in  a same block with IRQ_RESTORE() */
    #define IRQ_DISABLE_LOCAL()     {\
                                        unsigned long interrupt_state;\
                                        interrupt_state = (GET_CPSR() & 0x80UL);\
                                        IRQ_DISABLE();

    /** Macro to enable IRQs. This will set the I-flag in the CPSR to accept IRQs.*/
    /** This macro must be used in  a same block with IRQ_RESTORE() */
    #define IRQ_ENABLE_LOCAL()      {\
                                        unsigned long interrupt_state;\
                                        interrupt_state = (GET_CPSR() & 0x80UL);\
                                        IRQ_ENABLE();

    /** Macro to restore IRQ state. This will restore the I-flag */
    #define IRQ_RESTORE()               if(interrupt_state != 0)\
                                        {\
                                            IRQ_DISABLE();\
                                        }\
                                        else\
                                        {\
                                            IRQ_ENABLE();\
                                        }\
                                    }

    /** Macro to enable NMIs. This will clear the f-flag in the CPSR to accept NMIs (FIQ).
     ** After reset, NMIs can be enabled. After this, it is not possible to disable/mask them again,
     ** except by entering forcing a NMI to enter FIQ mode. */
    #define NMI_ENABLE()            __asm__ __volatile__ ("cpsie f")
    
    /** Macro containing the keywords to mark a function as interrupt
     ** service routine (ISR) for IRQs supporting interrupt nesting.
     ** This will signal the compiler to create the required assembler
     ** entry and exit code for an IRQ handler supporting nested
     ** interrupts i.e. during execution of the ISR interrupts with
     ** higher priority level can interrupt the ISR.
     ** GCC does NOT(!) automatically compile interrupt functions in ARM mode!!! */
    //#define FN_IRQ_NESTED         __interrupt
    // Currently interrupt nesting for ARM is not supported by GCC
           
    /** Macro containing the keywords to mark a function as interrupt
     ** service routine (ISR) for IRQs. This will signal the compiler
     ** to create the required assembler entry and exit code for
     ** an IRQ handler. During ISR execution, no other interrupts
     ** will be accepted.
     ** GCC does NOT(!) automatically compile interrupt functions in ARM mode!!! */
    #define FN_IRQ_NOT_NESTED       __attribute__ ((interrupt ("IRQ")))

    // -------------------------------------------------------------------------------
    // M A C R O S   F O R   N O N - M A S K A B L E   I N T E R R U P T S   ( N M I )
    // -------------------------------------------------------------------------------

    /** Keyword for a NMI handler function definition 
     ** GCC does NOT(!) automatically compile interrupt functions in ARM mode!!! */
    #define FN_NMI                  __attribute__ ((interrupt ("FIQ")))

#endif


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

/*****************************************************************************/
/* Global variable declarations ('extern', definition in C source)           */
/*****************************************************************************/

/*****************************************************************************/
/* Global function prototypes ('extern', definition in C source)             */
/*****************************************************************************/

#endif /* __FILE_VERSION_CHECK__ */
#endif /* __ABSTRACT_H__ */
