;************************************************************************
;*
;*             Copyright 2006 Mentor Graphics Corporation
;*                         All Rights Reserved.
;*
;* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS
;* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS
;* SUBJECT TO LICENSE TERMS.
;*
;************************************************************************

;************************************************************************
;*
;*  FILE NAME
;*
;*      rvct_arm.s
;*
;*  DESCRIPTION
;*
;*      This file contains the base ARM RVCT specific functions
;*
;*  FUNCTIONS
;*
;*      ESAL_AR_STK_Unsolicited_Restore
;*      ESAL_AR_STK_Unsolicited_Switch
;*      ESAL_AR_STK_Startup_SP_Set
;*      ESAL_AR_ISR_Vector_Table
;*      ESAL_AR_ISR_UNDEF_Except_Handler
;*      ESAL_AR_ISR_SWI_Except_Handler
;*      ESAL_AR_ISR_PREFETCH_Except_Handler
;*      ESAL_AR_ISR_DATA_Except_Handler
;*      ESAL_AR_ISR_IRQ_Int_Handler
;*      ESAL_AR_ISR_FIQ_Int_Handler
;*
;*  DEPENDENCIES
;*
;*      rvct_arm_defs.inc                               RVCT include file
;*
;*************************************************************************

;****************************
;* INCLUDE NECESSARY FILES  *
;****************************

#include   "nucleus_gen_cfg.h"
#include   "rvct_arm_defs.inc"

;**********************************
;* EXTERNAL FUNCTION DECLARATIONS *
;**********************************

;VOID           OS_Init_Entry(VOID);
;extern VOID    ESAL_AR_ISR_HOOK(VOID);

    IMPORT      OS_Init_Entry

    IF ESAL_AR_ISR_HOOK_ENABLED

    IMPORT ESAL_AR_ISR_HOOK

    ENDIF ; ESAL_AR_ISR_HOOK_ENABLED

;**********************************
;* EXTERNAL VARIABLE DECLARATIONS *
;**********************************

;extern VOID    *ESAL_GE_STK_System_SP;
;extern VOID    *ESAL_GE_STK_Exception_SP;
;extern INT     ESAL_GE_STK_Unsol_Switch_Req;
;extern VOID    (*ESAL_GE_STK_Unsol_Switch_OS_Entry)(VOID);
;extern INT     const ESAL_GE_MEM_ROM_Support_Enabled;
;extern VOID    **(*ESAL_GE_ISR_OS_Entry)(INT vector, VOID *stack_ptr);
;extern VOID    (*ESAL_GE_ISR_OS_Nested_Entry)(INT vector);
;extern VOID    (*ESAL_GE_ISR_Exception_Handler[ESAL_AR_NUM_EXCEPTIONS])(INT except_num, VOID *frame_ptr);
;extern INT     ESAL_GE_ISR_Executing;

    IMPORT      ESAL_GE_STK_System_SP
    IMPORT      ESAL_GE_STK_Exception_SP
    IMPORT      ESAL_GE_STK_Unsol_Switch_Req
    IMPORT      ESAL_GE_STK_Unsol_Switch_OS_Entry
    IMPORT      ESAL_GE_MEM_ROM_Support_Enabled
    IMPORT      ESAL_GE_ISR_OS_Entry
    IMPORT      ESAL_GE_ISR_OS_Nested_Entry
    IMPORT      ESAL_GE_ISR_Exception_Handler
    IMPORT      ESAL_GE_ISR_Executing

; Import linker produced labels

    IMPORT      |Image$$bss$$ZI$$Limit|

;****************************
;* VECTOR TABLE DECLARATION *
;****************************

    AREA        esal_vectors, CODE, READONLY
    PRESERVE8

;************************************************************************
;*
;*  FUNCTION
;*
;*      ESAL_AR_ISR_Vector_Table
;*
;*  DESCRIPTION
;*
;*      Identifies the start address of the actual vector table /
;*      exception handling code utilized by the target processor /
;*      architecture.  Other interrupt related data structures
;*      (priority tables / etc) will be defined in their respective
;*      esal_xx_isr.c file.
;*
;*  CALLED BY
;*
;*      Interrupt
;*
;*  CALLS
;*
;*      Interrupt Service Routine
;*
;*  INPUTS
;*
;*      None
;*
;*  OUTPUTS
;*
;*      None
;*
;************************************************************************
;VOID ESAL_AR_ISR_Vector_Table(VOID)

    CODE32 ; ESAL_AR_ISR_Vector_Table
    EXPORT ESAL_AR_ISR_Vector_Table
ESAL_AR_ISR_Vector_Table

    IF ESAL_AR_ISR_RESET_BRANCH

    B       ESAL_Entry

    ELSE

    LDR     PC, ESAL_AR_ISR_Reset_Addr

    ENDIF ; ESAL_AR_ISR_RESET_BRANCH

    LDR     PC, ESAL_AR_ISR_Undef_Addr
    LDR     PC, ESAL_AR_ISR_Software_Addr
    LDR     PC, ESAL_AR_ISR_Prefetch_Addr
    LDR     PC, ESAL_AR_ISR_Data_Addr
    NOP
    LDR     PC, ESAL_AR_ISR_IRQ_Addr
    LDR     PC, ESAL_AR_ISR_FIQ_Addr

ESAL_AR_ISR_Reset_Addr
    DCD ESAL_Entry
ESAL_AR_ISR_Undef_Addr
    DCD ESAL_AR_ISR_UNDEF_Except_Handler
ESAL_AR_ISR_Software_Addr
    DCD ESAL_AR_ISR_SWI_Except_Handler
ESAL_AR_ISR_Prefetch_Addr
    DCD ESAL_AR_ISR_PREFETCH_Except_Handler
ESAL_AR_ISR_Data_Addr
    DCD ESAL_AR_ISR_DATA_Except_Handler
ESAL_AR_ISR_IRQ_Addr
    DCD ESAL_AR_ISR_IRQ_Int_Handler
ESAL_AR_ISR_FIQ_Addr
    DCD ESAL_AR_ISR_FIQ_Int_Handler

;****************************
;* FUNCTIONS DECLARATIONS   *
;****************************

    AREA        esal_code, CODE, READONLY
    PRESERVE8

;**********************************
;* LOCAL VARIABLE DECLARATIONS    *
;**********************************

ESAL_AR_STK_Unsol_Switch_OS_Entry
    DCD ESAL_GE_STK_Unsol_Switch_OS_Entry
ESAL_AR_STK_BSS_End
    DCD |Image$$bss$$ZI$$Limit|
ESAL_AR_STK_System_SP
    DCD ESAL_GE_STK_System_SP
ESAL_AR_STK_Unsol_Switch_Req
    DCD ESAL_GE_STK_Unsol_Switch_Req
ESAL_Entry_ROM_Support_Enabled
    DCD ESAL_GE_MEM_ROM_Support_Enabled
ESAL_AR_ISR_Exception_SP
    DCD ESAL_GE_STK_Exception_SP
ESAL_AR_ISR_Executing
    DCD ESAL_GE_ISR_Executing
ESAL_AR_ISR_OS_Entry
    DCD ESAL_GE_ISR_OS_Entry
ESAL_AR_ISR_OS_Nested_Entry
    DCD ESAL_GE_ISR_OS_Nested_Entry
ESAL_AR_ISR_Exception_Handler
    DCD ESAL_GE_ISR_Exception_Handler


;************************************************************************
;*
;*   FUNCTION
;*
;*       Board_Lowlevel_Init
;*
;*   DESCRIPTION
;*
;*       Stub Board Init function that will be called if the BSP doesn't
;*       contain ROM support
;*
;*   CALLED BY
;*
;*       Reset
;*
;*   CALLS
;*
;*       None
;*
;*   INPUTS
;*
;*       None
;*
;*   OUTPUTS
;*
;*       None
;*
;***********************************************************************/
;VOID    Board_Lowlevel_Init(VOID)

    EXPORT  Board_Lowlevel_Init[WEAK]
Board_Lowlevel_Init

    ; Return to caller

    BX      LR

;************************************************************************
;*
;*   FUNCTION
;*
;*       ESAL_Entry
;*
;*   DESCRIPTION
;*
;*       This function is the entry point into ESAL.  Entry to this
;*       function is normally done through the reset mechanism
;*       (reset vector, jump from reset handler, etc) on the given
;*       processor / architecture.
;*
;*   CALLED BY
;*
;*       Reset
;*
;*   CALLS
;*
;*       ESAL_AR_STK_Startup_SP_Set
;*
;*   INPUTS
;*
;*       None
;*
;*   OUTPUTS
;*
;*       None
;*
;***********************************************************************/
;VOID    ESAL_Entry(VOID)

    ; Define the entry point for the debugger

    ENTRY

    EXPORT ESAL_Entry
ESAL_Entry

    ; Check if running from ROM (ROM support enabled)

    LDR     r0,ESAL_Entry_ROM_Support_Enabled
    LDR     r0,[r0]
    CMP     r0,#0
    BEQ     ESAL_Entry_ROM_Support_End

    ; Initialize memory controllers, chip-selects, etc, to allow
    ; access to volatile memory (RAM) when running from ROM.  Access
    ; to this memory must be done before entering a C environment
    ; so the stack can be set-up / utilized.
    ; NOTE:    When executing from RAM (debug environment) these operations
    ;          are normally performed by the debugger (via an initialization
    ;          script) or by a monitor or boot code on the target hardware.

    BL      Board_Lowlevel_Init

ESAL_Entry_ROM_Support_End

    ; Transfer control to ESAL_AR_STK_Startup_SP_Set function
    ; NOTE:   Control will not return here

    B       ESAL_AR_STK_Startup_SP_Set


;************************************************************************
;*
;*   FUNCTION
;*
;*       ESAL_AR_STK_Unsolicited_Restore
;*
;*   DESCRIPTION
;*
;*       This function restores the context of a stack frame as required
;*       by a given architecture (stack frame that contains all registers
;*       used by a given architecture)
;*
;*   CALLED BY
;*
;*       Operating System Services
;*
;*   CALLS
;*
;*       None
;*
;*   INPUTS
;*
;*       r0                                  Stack pointer of
;*                                           stack frame to be restored
;*
;*   OUTPUTS
;*
;*       None
;*
;***********************************************************************
;VOID    ESAL_AR_STK_Unsolicited_Restore(VOID *stack_ptr)

    CODE32 ; ESAL_AR_STK_Unsolicited_Restore
    EXPORT ESAL_AR_STK_Unsolicited_Restore
ESAL_AR_STK_Unsolicited_Restore

    ; Update System mode stack pointer to end-state

    ADD     r4,r0,#ESAL_AR_STK_MAX_FRAME_SIZE
    MOV     sp,r4

    ; Update System mode link register and r12 to end-state (banked-registers)

    LDR     lr,[r0,#ESAL_AR_STK_LR_OFFSET]
    LDR     r12,[r0,#ESAL_AR_STK_R12_OFFSET]    
    
    ; Skip stack type

    ADD     r0,r0,#4

    ; Restore r4-r11 from stack

    LDMIA   r0!,{r4-r11}    

#if (CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT > 0)

    ; Restore required floating point registers from the current stack.

    LDMIA   r0!,{r3}

    FMXR    FPSCR,r3

#if (CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT == 2)

    VLDMIA  r0!, {d0-d15}
    VLDMIA  r0!, {d16-d31}

#else

    VLDMIA  r0!,{d0-d15}

#endif  /* CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT == 2 */

#endif  /* CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT > 0  */
    
    ; Switch to FIQ mode and keep interrupts disabled (required to have access to SPSR register)
    ; NOTE:  The code following this point cannot result in a change to the FIQ mode SP

    MSR     CPSR_c,#(ESAL_AR_ISR_CPSR_FIQ_MODE :OR: ESAL_AR_ISR_CPSR_IRQ_BIT :OR: ESAL_AR_ISR_CPSR_FIQ_BIT)

    ; Get return address and SPSR from stack
    
    LDR     lr,[r0,#ESAL_AR_STK_MIN_PC_OFFSET]
    LDR     r1,[r0,#ESAL_AR_STK_MIN_SPSR_OFFSET]    
    
    ; Update SPSR

    MSR     SPSR_cxsf, r1    
    
    ; Restore minimal registers

    LDMIA   r0,{r0-r3}

    ; Return to point of interrupt

    MOVS    pc,lr


;***********************************************************************
;*
;*   FUNCTION
;*
;*       ESAL_AR_STK_Unsolicited_Switch
;*
;*   DESCRIPTION
;*
;*       This function saves the entire architecture context on the
;*       given stack and passes control to the OS
;*
;*   CALLED BY
;*
;*       Operating System Services
;*
;*   CALLS
;*
;*       None
;*
;*   INPUTS
;*
;*       r0                                  Pointer to stack pointer
;*
;*   OUTPUTS
;*
;*       None
;*
;***********************************************************************
;VOID  ESAL_AR_STK_Unsolicited_Switch(VOID **stack_ptr)

    CODE32 ; ESAL_AR_STK_Unsolicited_Switch
    EXPORT ESAL_AR_STK_Unsolicited_Switch
ESAL_AR_STK_Unsolicited_Switch

    ; Get stack pointer

    LDR     sp,[r0]

#if (CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT > 0)

    ; Save required floating point registers on the current stack.

#if (CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT == 2)

    VSTMDB  sp!, {d16-d31}
    VSTMDB  sp!, {d0-d15}

#else

    VSTMDB  sp!,{d0-d15}

#endif  /* CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT == 2 */

    FMRX    r3,FPSCR

    STMDB   sp!,{r3}

#endif  /* CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT > 0 */

    ; Put stack type in r3

    MOV     r3,#1

    ; Save remaining registers and stack type on stack

    STMDB   sp!,{r3-r11}

    ; Save new stack pointer in save location

    STR     sp,[r0]

    ; Clear switch flag

    LDR     r0,ESAL_AR_STK_Unsol_Switch_Req
    MOV     r1,#0
    STR     r1,[r0]

    ; Switch to the system stack

    LDR     r0,ESAL_AR_STK_System_SP
    LDR     sp,[r0]

    ; Transfer control to OS unsolicited stack switch entry point

    LDR     r0,ESAL_AR_STK_Unsol_Switch_OS_Entry
    LDR     r0,[r0]
    BX      r0


;************************************************************************
;*
;*  FUNCTION
;*
;*      ESAL_AR_STK_Startup_SP_Set
;*
;*  DESCRIPTION
;*
;*      This function sets the architecture stack pointer to an address
;*      that can be used during initialization.  This can include on-chip
;*      SRAM, available RAM not used by the application during
;*      initialization, etc.
;*
;*  CALLED BY
;*
;*      ESAL_Entry
;*
;*  CALLS
;*
;*      ESAL_TS_RTE_Lowlevel_Initialize
;*
;*  INPUTS
;*
;*      None
;*
;*  OUTPUTS
;*
;*      None
;*
;************************************************************************
;VOID    ESAL_AR_STK_Startup_SP_Set(VOID)

    CODE32 ; ESAL_AR_STK_Startup_SP_Set
    EXPORT ESAL_AR_STK_Startup_SP_Set
ESAL_AR_STK_Startup_SP_Set

    ; Switch to system mode (keeping interrupts disabled) to set-up the
    ; system mode stack

    MSR     CPSR_c,#(ESAL_AR_ISR_CPSR_SYS_MODE :OR: ESAL_AR_ISR_CPSR_IRQ_BIT :OR: ESAL_AR_ISR_CPSR_FIQ_BIT)

#if (CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT > 0)

#if (CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT == 2)

    ; Enable access to CP10 and CP11 in Access Control Register

    MRC     p15,#0,r0,c1,c0,#2
    MOV     r1,#0xF0
    LSL     r1,r1,#16
    ORR     r0,r0,r1
    MCR     p15,#0,r0,c1,c0,#2

#endif  /* CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT == 2 */

    ; Enable the VFP

    MOV     r0,#ESAL_AR_STK_VFP_ENABLE
    FMXR    FPEXC,r0
    MOV     r0,#0x03000000
    FMXR    FPSCR,r0

#endif  /* CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT > 0 */

    ; Get start address of available memory that can be used for the
    ; startup stack.

    LDR     r0,ESAL_AR_STK_BSS_End

    ; Add stack size to get usable stack pointer

    ADD     r0,r0,#ESAL_AR_STK_STARTUP_STACK_SIZE

    ; Align the stack pointer as required.

    BIC     r0,r0,#ESAL_AR_STK_ALIGNMENT_MASK
    MOV     sp,r0

    ; Jump to toolset run-time environment setup function - control will not return.

    B       ESAL_TS_RTE_Lowlevel_Initialize


;************************************************************************
;*
;*   FUNCTION
;*
;*       ESAL_TS_RTE_Lowlevel_Initialize
;*
;*   DESCRIPTION
;*
;*       This function initializes registers and hardware as required
;*       for a run-time environment.  Many toolsets require a certain
;*       environment to be set-up to allow correct run-time execution
;*       in a C environment.  This may include initializing certain
;*       architecture registers (base registers, mode registers, etc)
;*       and anything else specified in the toolset documentation.
;*
;*   CALLED BY
;*
;*       ESAL_AR_STK_Startup_SP_Set
;*
;*   CALLS
;*
;*       OS_Init_Entry                          OS Entry Point
;*
;*   INPUTS
;*
;*       None
;*
;*   OUTPUTS
;*
;*       None
;*
;************************************************************************
;VOID    ESAL_TS_RTE_Lowlevel_Initialize(VOID)

    CODE32 ; ESAL_TS_RTE_Lowlevel_Initialize
    EXPORT ESAL_TS_RTE_Lowlevel_Initialize
ESAL_TS_RTE_Lowlevel_Initialize

    ; Zero out the lr to provide a nicer debug environment (call stack-trace)

    MOV     r14,#0

    ; Call OS entry point
    ; NOTE:   Control will not return here

    B       OS_Init_Entry


;************************************************************************
;*
;*   FUNCTION
;*
;*       ESAL_TS_RTE_SP_Write
;*
;*   DESCRIPTION
;*
;*       This function writes the stack pointer.  This function is only
;*       used by toolsets where this operation cannot be done with inline
;*       assembler.
;*
;*   CALLED BY
;*
;*       OS Services
;*       ESAL_AR_ISR_Initialize
;*
;*   CALLS
;*
;*       None
;*
;*   INPUTS
;*
;*       stk_ptr                                     Stack pointer to set
;*
;*   OUTPUTS
;*
;*       None
;*
;************************************************************************
;VOID    ESAL_TS_RTE_SP_Write(VOID *stk_ptr)

    CODE32 ; ESAL_TS_RTE_SP_Write
    EXPORT ESAL_TS_RTE_SP_Write
ESAL_TS_RTE_SP_Write

    ; Set the stack pointer

    MOV     sp,r0

    ; Return to caller

    BX      lr


;************************************************************************
;*
;*  FUNCTION
;*
;*      ESAL_TS_STK_Solicited_Restore
;*
;*  DESCRIPTION
;*
;*      This function restores the context of a stack frame as required
;*      by a given toolset (stack frame that contains registers
;*      required to be saved across function call boundaries)
;*
;*  CALLED BY
;*
;*      Operating System Services
;*
;*  CALLS
;*
;*      None
;*
;*  INPUTS
;*
;*      stack_ptr                           Stack pointer of
;*                                          stack frame to be restored
;*
;*  OUTPUTS
;*
;*      None
;*
;************************************************************************
;VOID    ESAL_TS_STK_Solicited_Restore(VOID *stack_ptr)

    CODE32 ; ESAL_TS_STK_Solicited_Restore
    EXPORT ESAL_TS_STK_Solicited_Restore
ESAL_TS_STK_Solicited_Restore

    ; Switch to the stack pointer passed-in and skip stack type

    ADD     r0,r0,#4
    MOV     sp,r0

    ; Restore all registers stored in the solicited
    ; stack frame.

    LDMIA   sp!,{r4-r11,lr}

#if (CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT > 0)

    ; Restore required floating point registers from the current stack.

    LDMIA   sp!,{r3}

    FMXR    FPSCR,r3

    VLDMIA  sp!, {d8-d15}

#endif  /* CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT > 0 */

    ; Use the architecture's return from function call
    ; mechanism to transfer control to the stack frame
    ; return address.

    BX      lr


;************************************************************************
;*
;*  FUNCTION
;*
;*      ESAL_TS_STK_Solicited_Switch
;*
;*  DESCRIPTION
;*
;*      This function saves the necessary registers, designated by a
;*      given toolset, to be preserved across a function call
;*      boundary.  Control is then transferred to the designated
;*      call-back function with the designated call-back parameter.
;*
;*  CALLED BY
;*
;*      Operating System Services
;*
;*  CALLS
;*
;*      <call back function>
;*
;*  INPUTS
;*
;*      call_back_param                     Parameter passed to callback
;*                                          function
;*      call_back                           Call back function pointer
;*      stack_ptr                           Pointer to stack pointer
;*                                          storage address
;*
;*  OUTPUTS
;*
;*      None
;*
;************************************************************************
;VOID    ESAL_TS_STK_Solicited_Switch(VOID *call_back_param,
;                                     VOID (*call_back)(VOID),
;                                     VOID **stack_ptr)

    CODE32 ; ESAL_TS_STK_Solicited_Switch
    EXPORT ESAL_TS_STK_Solicited_Switch
ESAL_TS_STK_Solicited_Switch

#if (CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT > 0)

    ; Save required floating point registers on the current stack.

    VSTMDB   sp!,{d8-d15}

    FMRX    r3,FPSCR

    STMDB   sp!,{r3}

#endif  /* CFG_NU_OS_ARCH_ARM_COM_FPU_SUPPORT > 0 */

    ; Save the toolset required registers to the current stack.
    ; NOTE:   The format of this stack frame is contained in esal_ts_stk_defs.h
    ;         (structure name is ESAL_TS_STK).

    STMDB   sp!,{r4-r11,lr}

    ; Save stack type (solicited stack = 0) on top of stack

    MOV     r4,#0
    STR     r4,[sp, #-4]!

    ; Save resultant stack pointer back to location passed in

    STR     sp,[r2]

    ; Switch to the system stack

    LDR     r2,ESAL_AR_STK_System_SP
    LDR     sp,[r2]

    ; Transfer control to callback function (call-back parameter is
    ; already in register r0).

    BX      r1


;************************************************************************
;*
;*  FUNCTION
;*
;*      ESAL_AR_ISR_UNDEF_Except_Handler
;*
;*  DESCRIPTION
;*
;*      Handler for ARM Undefined Instruction Exception
;*
;*  CALLED BY
;*
;*      Interrupt / Exception Vector Table
;*
;*  CALLS
;*
;*      Registered Exception Handler
;*
;*  INPUTS
;*
;*      None
;*
;*  OUTPUTS
;*
;*      None
;*
;************************************************************************
;static VOID    ESAL_AR_ISR_UNDEF_Except_Handler(VOID)

    CODE32 ; ESAL_AR_ISR_UNDEF_Except_Handler
ESAL_AR_ISR_UNDEF_Except_Handler

    ; Disable FIQs and IRQs (stay in undefined mode)

    MSR     CPSR_c,#(ESAL_AR_ISR_CPSR_UND_MODE :OR: ESAL_AR_ISR_CPSR_IRQ_BIT :OR: ESAL_AR_ISR_CPSR_FIQ_BIT)

    ; Update lr to exception address

    SUB     lr,lr,#4

    ; Switch to the exception stack

    LDR     sp,ESAL_AR_ISR_Exception_SP
    LDR     sp,[sp]

    ; Save minimum context for exception

    ESAL_AR_STK_MIN_EXCEPT_SAVE

    ; Put ESAL exception id in r0

    MOV     r0,#ESAL_AR_UNDEF_EXCEPT_VECTOR_ID

    ; Get address of exception handler table

    LDR     r2,ESAL_AR_ISR_Exception_Handler

    ; Put min stack frame address in 2nd parameter register

    MOV     r1,sp

    ; Get address of exception handler for the executing exception

    LDR     r2,[r2,r0,LSL #2]

    ; Jump to exception handler (saving return address)

    MOV     lr,pc
    BX      r2

    ; Return from the exception

    ESAL_AR_STK_MIN_EXCEPT_RESTORE


;************************************************************************
;*
;*  FUNCTION
;*
;*      ESAL_AR_ISR_SWI_Except_Handler
;*
;*  DESCRIPTION
;*
;*      Handler for ARM Software Interrupt Exception
;*
;*  CALLED BY
;*
;*      Interrupt / Exception Vector Table
;*
;*  CALLS
;*
;*      Registered Exception Handler
;*
;*  INPUTS
;*
;*      None
;*
;*  OUTPUTS
;*
;*      None
;*
;************************************************************************
;static VOID    ESAL_AR_ISR_SWI_Except_Handler(VOID)

    CODE32 ; ESAL_AR_ISR_SWI_Except_Handler
ESAL_AR_ISR_SWI_Except_Handler

    ; Save minimum context for exception

    ESAL_AR_STK_MIN_EXCEPT_SAVE

    ; Put ESAL exception id in r0

    MOV     r0,#ESAL_AR_SWI_EXCEPT_VECTOR_ID

    ; Get address of exception handler table

    LDR     r2,ESAL_AR_ISR_Exception_Handler

    ; Put min stack frame address in 2nd parameter register

    MOV     r1,sp

    ; Get address of exception handler for the executing exception

    LDR     r2,[r2,r0,LSL #2]

    ; Jump to exception handler (saving return address)

    MOV     lr,pc
    BX      r2

    ; Return from the exception

    ESAL_AR_STK_MIN_EXCEPT_RESTORE


;************************************************************************
;*
;*  FUNCTION
;*
;*      ESAL_AR_ISR_PREFETCH_Except_Handler
;*
;*  DESCRIPTION
;*
;*      Handler for ARM Prefetch Abort Exception
;*
;*  CALLED BY
;*
;*      Interrupt / Exception Vector Table
;*
;*  CALLS
;*
;*      Registered Exception Handler
;*
;*  INPUTS
;*
;*      None
;*
;*  OUTPUTS
;*
;*      None
;*
;************************************************************************
;static VOID    ESAL_AR_ISR_PREFETCH_Except_Handler(VOID)

    CODE32 ; ESAL_AR_ISR_PREFETCH_Except_Handler
ESAL_AR_ISR_PREFETCH_Except_Handler

    ; Disable FIQs and IRQs (stay in abort mode)

    MSR     CPSR_c,#(ESAL_AR_ISR_CPSR_ABT_MODE :OR: ESAL_AR_ISR_CPSR_IRQ_BIT :OR: ESAL_AR_ISR_CPSR_FIQ_BIT)

    ; Update lr to exception address

    SUB     lr,lr,#4

    ; Switch to the exception stack

    LDR     sp,ESAL_AR_ISR_Exception_SP
    LDR     sp,[sp]

    ; Save minimum context for exception

    ESAL_AR_STK_MIN_EXCEPT_SAVE

    ; Put ESAL exception ID in r0

    MOV     r0,#ESAL_AR_PREFETCH_EXCEPT_VECTOR_ID

    ; Get address of exception handler table

    LDR     r2,ESAL_AR_ISR_Exception_Handler

    ; Put min stack frame address in 2nd parameter register

    MOV     r1,sp

    ; Get address of exception handler for the executing exception

    LDR     r2,[r2,r0,LSL #2]

    ; Jump to exception handler (saving return address)

    MOV     lr,pc
    BX      r2

    ; Return from the exception

    ESAL_AR_STK_MIN_EXCEPT_RESTORE


;************************************************************************
;*
;*  FUNCTION
;*
;*      ESAL_AR_ISR_DATA_Except_Handler
;*
;*  DESCRIPTION
;*
;*      Handler for ARM Data Abort Exception
;*
;*  CALLED BY
;*
;*      Interrupt / Exception Vector Table
;*
;*  CALLS
;*
;*      Registered Exception Handler
;*
;*  INPUTS
;*
;*      None
;*
;*  OUTPUTS
;*
;*      None
;*
;************************************************************************
;static VOID    ESAL_AR_ISR_DATA_Except_Handler(VOID)

    CODE32 ; ESAL_AR_ISR_DATA_Except_Handler
ESAL_AR_ISR_DATA_Except_Handler

    ; Disable FIQs and IRQs (stay in abort mode)

    MSR     CPSR_c,#(ESAL_AR_ISR_CPSR_ABT_MODE :OR: ESAL_AR_ISR_CPSR_IRQ_BIT :OR: ESAL_AR_ISR_CPSR_FIQ_BIT)

    ; Update lr to exception address

    SUB     lr,lr,#8

    ; Switch to the exception stack

    LDR     sp,ESAL_AR_ISR_Exception_SP
    LDR     sp,[sp]

    ; Save minimum context for exception

    ESAL_AR_STK_MIN_EXCEPT_SAVE

    ; Put ESAL exception ID in r0

    MOV     r0,#ESAL_AR_DATA_EXCEPT_VECTOR_ID

    ; Get address of exception handler table

    LDR     r2,ESAL_AR_ISR_Exception_Handler

    ; Put min stack frame address in 2nd parameter register

    MOV     r1,sp

    ; Get address of exception handler for the executing exception

    LDR     r2,[r2,r0,LSL #2]

    ; Jump to exception handler (saving return address)

    MOV     lr,pc
    BX      r2

    ; Return from the exception

    ESAL_AR_STK_MIN_EXCEPT_RESTORE


;************************************************************************
;*
;*  FUNCTION
;*
;*      ESAL_AR_ISR_IRQ_Int_Handler
;*
;*  DESCRIPTION
;*
;*      Handler for ARM IRQ Interrupt
;*
;*  CALLED BY
;*
;*      Interrupt / Exception Vector Table
;*
;*  CALLS
;*
;*      Registered Interrupt Handler
;*      ESAL_AR_STK_Unsolicited_Switch
;*
;*  INPUTS
;*
;*      None
;*
;*  OUTPUTS
;*
;*      None
;*
;************************************************************************
;static VOID    ESAL_AR_ISR_IRQ_Int_Handler(VOID)

    CODE32 ; ESAL_AR_ISR_IRQ_Int_Handler
ESAL_AR_ISR_IRQ_Int_Handler

    IF ESAL_AR_ISR_HOOK_ENABLED

    ; Save minimal registers to IRQ stack

    STMIA   sp!,{r0-r1,lr}

    ; Jump to hook function

    BL      ESAL_AR_ISR_HOOK

    ; Restore minimal registers from IRQ stack

    LDMDB   sp!,{r0-r1,lr}

    ENDIF ; ESAL_AR_ISR_HOOK_ENABLED

    ; Adjust lr to interrupt address

    SUB     lr,lr,#4

    ; Save minimum architecture registers to stack for interrupt

    ESAL_AR_STK_MIN_INT_SAVE

    ; Put ESAL interrupt ID in r0 (1st parameter)

    MOV     r0,#ESAL_AR_IRQ_INT_VECTOR_ID

    ; stack pointer in r1 (2nd parameter)

    MOV     r1,sp

    ; Check if this interrupt occurred during execution of
    ; another interrupt (nested)

    LDR     r2,ESAL_AR_ISR_Executing
    LDR     r2,[r2]
    CMP     r2,#0

    ; Switch stack if first interrupt (not nested)

    LDREQ   sp,ESAL_AR_STK_System_SP
    LDREQ   sp,[sp]

    ; Get address of OS entry for correct interrupt handler
    ; (nested or non-nested)

    LDREQ   r2,ESAL_AR_ISR_OS_Entry
    LDRNE   r2,ESAL_AR_ISR_OS_Nested_Entry
    LDR     r2,[r2]

    ; Get return address and transfer
    ; control to OS entry for interrupt handling

    ADRNE   lr,ESAL_AR_ISR_Nested_IRQ_Restore
    MOVEQ   lr,pc
    BX      r2

    ; Check if context switch is required as a result of
    ; the interrupt service routine

    LDR     r2,ESAL_AR_STK_Unsol_Switch_Req
    LDR     r2,[r2]
    CMP     r2,#0

    ; Perform context switch if required

    BNE     ESAL_AR_STK_Unsolicited_Switch

    ; No context switch required, restore minimal context and
    ; return to point of interrupt

    ; Get system stack pointer in r0

    LDR     r0,[r0]

    ; Restore minimum registers from stack and return from interrupt

    ESAL_AR_STK_MIN_INT_RESTORE

ESAL_AR_ISR_Nested_IRQ_Restore

    ; Put the stack pointer in r0

    MOV     r0,sp

    ; Restore minimum registers from stack and return from interrupt

    ESAL_AR_STK_MIN_INT_RESTORE


;************************************************************************
;*
;*  FUNCTION
;*
;*      ESAL_AR_ISR_FIQ_Int_Handler
;*
;*  DESCRIPTION
;*
;*      Handler for ARM FIQ Interrupt
;*
;*  CALLED BY
;*
;*      Interrupt / Exception Vector Table
;*
;*  CALLS
;*
;*      Registered Interrupt Handler
;*      ESAL_AR_STK_Unsolicited_Switch
;*
;*  INPUTS
;*
;*      None
;*
;*  OUTPUTS
;*
;*      None
;*
;************************************************************************
;static VOID    ESAL_AR_ISR_FIQ_Int_Handler(VOID)

    CODE32 ; ESAL_AR_ISR_FIQ_Int_Handler
ESAL_AR_ISR_FIQ_Int_Handler

    ; Check if FIQ interrupt occurred during first few instructions
    ; of an IRQ interrupt - this is considered a "special" nested case
    ; NOTE: Use FIQ banked register r8 to do this check (eliminates need to push on stack)

    ; Get SPSR for current interrupt

    MRS     r8,SPSR

    ; Clear all but mode bits from SPSR

    AND     r9,r8,#ESAL_AR_ISR_CPSR_MODE_MASK

    ; Check to see if processor was in IRQ mode when FIQ occurred

    TEQ     r9,#ESAL_AR_ISR_CPSR_IRQ_MODE

    ; If SPSR indicates in IRQ mode, disable FIQs in SPSR and return to point of interrupt
    ; NOTE: This will allow the IRQ to continue processing and the FIQ interrupt will be
    ;       picked-up as soon as the IRQ interrupt handler re-enables FIQs

    BNE     no_irq_pending
    ORR     r8,r8,#ESAL_AR_ISR_CPSR_FIQ_BIT
    MSR     SPSR_cxsf, r8
    SUBS    pc,lr,#4
no_irq_pending

    IF ESAL_AR_ISR_HOOK_ENABLED

    ; Save minimal registers to FIQ stack

    STMIA   sp!,{r0-r1,lr}

    ; Jump to hook function

    BL      ESAL_AR_ISR_HOOK

    ; Restore minimal registers from FIQ stack

    LDMDB   sp!,{r0-r1,lr}

    ENDIF ; ESAL_AR_ISR_HOOK_ENABLED

    ; Adjust lr to interrupt address

    SUB     lr,lr,#4

    ; Save minimum architecture registers to stack for interrupt

    ESAL_AR_STK_MIN_INT_SAVE

    ; Put ESAL interrupt ID number in r0 (1st parameter)

    MOV     r0,#ESAL_AR_FIQ_INT_VECTOR_ID

    ; stack pointer in r1 (2nd parameter)

    MOV     r1,sp

    ; Check if this interrupt occurred during execution of
    ; another interrupt (nested)

    LDR     r2,ESAL_AR_ISR_Executing
    LDR     r2,[r2]
    CMP     r2,#0


    LDREQ   sp,ESAL_AR_STK_System_SP
    LDREQ   sp,[sp]

    ; Get address of OS entry for correct interrupt handler
    ; (nested or non-nested)

    LDREQ   r2,ESAL_AR_ISR_OS_Entry

    LDRNE   r2,ESAL_AR_ISR_OS_Nested_Entry
    LDR     r2,[r2]

    ; Get return address and transfer
    ; control to OS entry for interrupt handling

    ADRNE   lr,ESAL_AR_ISR_Nested_FIQ_Restore
    MOVEQ   lr,pc
    BX      r2

    ; Check if context switch is required as a result of
    ; the interrupt service routine

    LDR     r2,ESAL_AR_STK_Unsol_Switch_Req
    LDR     r2,[r2]
    CMP     r2,#0

    ; Perform context switch if required

    BNE     ESAL_AR_STK_Unsolicited_Switch

    ; No context switch required, restore minimal context and
    ; return to point of interrupt

    ; Get system stack pointer in r0

    LDR     r0,[r0]

    ; Restore minimum registers from stack and return from interrupt

    ESAL_AR_STK_MIN_INT_RESTORE

ESAL_AR_ISR_Nested_FIQ_Restore

    ; Put the stack pointer in r0

    MOV     r0,sp

    ; Restore minimum registers from stack and return from interrupt

    ESAL_AR_STK_MIN_INT_RESTORE

    END
