#************************************************************************
#*
#*             Copyright 2011 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
#*
#*      csgnu_mips.s
#*
#*  DESCRIPTION
#*
#*      This file contains the base MIPS CSGNU specific functions
#*
#*  FUNCTIONS
#*
#*      ESAL_AR_STK_Unsolicited_Restore
#*      ESAL_AR_STK_Unsolicited_Switch
#*      ESAL_AR_STK_Startup_SP_Set
#*      ESAL_AR_ISR_Vector_Table
#*
#*  DEPENDENCIES
#*
#*      csgnu_mips_defs.inc                 CSGNU include file
#*
#*************************************************************************

#****************************
#* INCLUDE NECESSARY FILES  *
#****************************

    .include    "csgnu_mips_defs.inc"

#**********************************
#* EXTERNAL FUNCTION DECLARATIONS *
#**********************************

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

    .extern OS_Init_Entry

    .if ESAL_AR_ISR_HOOK_ENABLED

    .extern 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;

    .extern ESAL_GE_STK_System_SP
    .extern ESAL_GE_STK_Exception_SP
    .extern ESAL_GE_STK_Unsol_Switch_Req
    .extern ESAL_GE_STK_Unsol_Switch_OS_Entry    
	.extern ESAL_GE_MEM_ROM_Support_Enabled
    .extern ESAL_GE_ISR_OS_Entry
    .extern ESAL_GE_ISR_OS_Nested_Entry
    .extern ESAL_GE_ISR_Exception_Handler
    .extern ESAL_GE_ISR_Executing

#**********************************
#* LOCAL VARIABLE DECLARATIONS    *
#**********************************

ESAL_AR_STK_Unsol_Switch_OS_Entry:
    .long ESAL_GE_STK_Unsol_Switch_OS_Entry
ESAL_AR_STK_BSS_End:
    .long _ld_bss_end
ESAL_AR_STK_System_SP:
    .long ESAL_GE_STK_System_SP
ESAL_AR_STK_Unsol_Switch_Req:
    .long ESAL_GE_STK_Unsol_Switch_Req
ESAL_Entry_ROM_Support_Enabled:
    .long ESAL_GE_MEM_ROM_Support_Enabled
ESAL_AR_ISR_Exception_SP:
    .long ESAL_GE_STK_Exception_SP
ESAL_AR_ISR_Executing:
    .long ESAL_GE_ISR_Executing
ESAL_AR_ISR_OS_Entry:
    .long ESAL_GE_ISR_OS_Entry
ESAL_AR_ISR_Exception_Handler:
    .long ESAL_GE_ISR_Exception_Handler


# Import linker produced labels

    .extern     _ld_bss_end

#****************************
#* VECTOR TABLE DECLARATION *
#****************************

    .section    esal_vectors, "ax"
    .set        noreorder

#************************************************************************
#*
#*  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)

    .global ESAL_AR_ISR_Vector_Table
ESAL_AR_ISR_Vector_Table:

#******************************
#* TLB Exception (offset 0x000)
#******************************

    # Branch to exception handler

    j       ESAL_AR_ISR_General_Exception_Handler
    nop

#********************************
#* Cache Exception (offset 0x100)
#********************************

    # Offset origin by 0x0100

    .org    0x0100

    # Branch to exception handler

    j       ESAL_AR_ISR_General_Exception_Handler
    nop

#**********************************
#* General Exception (offset 0x180)
#**********************************

    # Offset origin by 0x0180

    .org    0x0180

    # Branch to exception handler

    j       ESAL_AR_ISR_General_Exception_Handler
    nop
    
#**********************************
#* Special Interrupt (offset 0x200)
#**********************************

    # Offset origin by 0x200

    .org    0x0200

    # Branch to exception handler

    j       ESAL_AR_ISR_Special_Interrupt_Handler
    nop




    .global ESAL_AR_ISR_Vector_Table_End
ESAL_AR_ISR_Vector_Table_End:

#***************************************
#* Reset / NMI Exception (fixed address)
#***************************************

    .section    .esal_reset_exception, "ax"
    .set        noreorder

    # Branch to ESAL_Entry (entry point for OS)

    la     $8, ESAL_Entry
    jr     $8
    nop



#****************************
#* FUNCTIONS DECLARATIONS   *
#****************************

    .section        esal_code, "ax"
    .set            noreorder

#************************************************************************
#*
#*   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

    .global  start
start:

    .global ESAL_Entry
ESAL_Entry:

    # Check if running from ROM (ROM support enabled)

    la  $8, ESAL_GE_MEM_ROM_Support_Enabled
    lw  $8, 0($8)
    BEQ $0, $8, ESAL_Entry_ROM_Support_End
    ssnop

    # 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.

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)

    .global ESAL_AR_STK_Unsolicited_Restore
ESAL_AR_STK_Unsolicited_Restore:

    # Switch to the stack pointer passed-in

    or      $sp, $0, $4

    # Restore all registers stored in the unsolicited
    # stack frame.

    lw      $16,  4 ($sp)
    lw      $17,  8 ($sp)
    lw      $18,  12($sp)
    lw      $19,  16($sp)
    lw      $20,  20($sp)
    lw      $21,  24($sp)
    lw      $22,  28($sp)
    lw      $23,  32($sp)
    lw      $30,  36($sp)

    # Disable assembler use of the $at ($1) register
    
    .set     noat
    
    # Restore remaining registers from stack
    
    lw       $1,  40($sp)
    lw       $2,  44($sp)
    lw       $3,  48($sp)
    lw       $4,  52($sp)
    lw       $5,  56($sp)
    lw       $6,  60($sp)
    lw       $7,  64($sp)
    lw       $8,  68($sp)
    lw       $9,  72($sp)
    lw       $10, 76($sp)
    lw       $11, 80($sp)
    lw       $12, 84($sp)
    lw       $13, 88($sp)
    lw       $14, 92($sp)
    lw       $15, 96($sp)
    lw       $24, 100($sp)
    lw       $25, 104($sp)

    # Restore high register
    
    lw       $27, 108($sp)
    mthi     $27

    # Restore low register
    
    lw       $27, 112($sp)
    mtlo     $27
    lw       $31, 116($sp)

    # Restore status register (SR)

    lw       $27, 120($sp)
    mtc0     $27, $12
    ssnop
    ssnop
    ehb

    # Get return address from stack frame (EPC)

    lw       $27, 124($sp)
    mtc0     $27, $14
    ssnop
    ssnop
    ehb

.if ESAL_AR_STK_FPU_SUPPORT

    # Restoring All FPU registers
    
    lwc1    $f0,  128($sp)
    lwc1    $f1,  132($sp)
    lwc1    $f2,  136($sp)
    lwc1    $f3,  140($sp)
    lwc1    $f4,  144($sp)
    lwc1    $f5,  148($sp)
    lwc1    $f6,  152($sp)
    lwc1    $f7,  156($sp)
    lwc1    $f8,  160($sp)
    lwc1    $f9,  164($sp)
    lwc1    $f10, 168($sp)
    lwc1    $f11, 172($sp)
    lwc1    $f12, 176($sp)
    lwc1    $f13, 180($sp)
    lwc1    $f14, 184($sp)
    lwc1    $f15, 188($sp)
    lwc1    $f16, 192($sp)
    lwc1    $f17, 196($sp)
    lwc1    $f18, 200($sp)
    lwc1    $f19, 204($sp)
    lwc1    $f20, 208($sp)
    lwc1    $f21, 212($sp)
    lwc1    $f22, 216($sp)
    lwc1    $f23, 220($sp)
    lwc1    $f24, 224($sp)
    lwc1    $f25, 228($sp)
    lwc1    $f26, 232($sp)
    lwc1    $f27, 236($sp)
    lwc1    $f28, 240($sp)
    lwc1    $f29, 244($sp)
    lwc1    $f30, 248($sp)
    lwc1    $f31, 252($sp)
    lwc1    $27,  256($sp)
    ctc1    $27,  $31

.endif

    # Recover stack space 

    addi     $sp, $sp, ESAL_AR_STK_MAX_FRAME_SIZE

    # return to point of interrupt

    eret

    # Re-enable assembler use of the $at ($1) register
    
    .set     at



#***********************************************************************
#*
#*   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)

    .global ESAL_AR_STK_Unsolicited_Switch
ESAL_AR_STK_Unsolicited_Switch:

    # Switch to the stack pointer at location passed in

    lw      $sp, 0($2)

    # Save remaining registers that are part of the architecture
    # stack frame (ESAL_AR_STK defined in esal_ar_stk_defs.h).  
    # NOTE:   Only the minimum stack registers should be saved before entering
    #         this function (ESAL_AR_STK_MIN defined in esal_ar_stk_defs.h). */

    # Set stack pointer for correct starting spot

    addi    $sp, $sp, -(ESAL_AR_STK_MAX_FRAME_SIZE - ESAL_AR_STK_MIN_FRAME_SIZE)

    sw      $16, 4 ($sp)
    sw      $17, 8 ($sp)
    sw      $18, 12($sp)
    sw      $19, 16($sp)
    sw      $20, 20($sp)
    sw      $21, 24($sp)
    sw      $22, 28($sp)
    sw      $23, 32($sp)
    sw      $30, 36($sp)

.if ESAL_AR_STK_FPU_SUPPORT

    # Restoring All FPU registers

    swc1    $f0,  40($sp)
    swc1    $f1,  44($sp)
    swc1    $f2,  48($sp)
    swc1    $f3,  52($sp)
    swc1    $f4,  56($sp)
    swc1    $f5,  60($sp)
    swc1    $f6,  64($sp)
    swc1    $f7,  68($sp)
    swc1    $f8,  72($sp)
    swc1    $f9,  76($sp)
    swc1    $f10, 80($sp)
    swc1    $f11, 84($sp)
    swc1    $f12, 88($sp)
    swc1    $f13, 92($sp)
    swc1    $f14, 96($sp)
    swc1    $f15, 100($sp)
    swc1    $f16, 104($sp)
    swc1    $f17, 108($sp)
    swc1    $f18, 112($sp)
    swc1    $f19, 116($sp)
    swc1    $f20, 120($sp)
    swc1    $f21, 124($sp)
    swc1    $f22, 128($sp)
    swc1    $f23, 132($sp)
    swc1    $f24, 136($sp)
    swc1    $f25, 140($sp)
    swc1    $f26, 144($sp)
    swc1    $f27, 148($sp)
    swc1    $f28, 152($sp)
    swc1    $f29, 156($sp)
    swc1    $f30, 160($sp)
    swc1    $f31, 164($sp)
    cfc1    $27,  $31
    swc1    $27,  168($sp)

.endif

    # Save stack type (unsolicited stack = 1) on top of stack.
    # 1 is for the architecture stack type

    li      $8, 1
    sw      $8, 0($sp)

    # Save resultant stack pointer back to return register

    sw      $sp, 0($2)

    # Switch to the system stack

    la  	$8, ESAL_GE_STK_System_SP
    lw    	$sp, 0($8)    
    
    # Clear flag for architecture stack switch required

    la      $8, ESAL_GE_STK_Unsol_Switch_Req
    sw      $0, 0($8)

    # Transfer control to OS designated function
    # NOTE:   Control will not return here.

    la      $8, ESAL_GE_STK_Unsol_Switch_OS_Entry
    lw      $8, 0($8)
    j       $8
    nop



#************************************************************************
#*
#*  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)

    .global ESAL_AR_STK_Startup_SP_Set
ESAL_AR_STK_Startup_SP_Set:

    #  Initializing the Status Register

    li     $8, ESAL_AR_STK_SR_CU_BITS
    mtc0   $8, $12
    ssnop
    ssnop
    ehb

.if ESAL_AR_STK_FPU_SUPPORT

    # Clear floating point FCR31

    ctc1    $0, $31
    ssnop
    ssnop
    ehb

.endif

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

    la      $8, _ld_bss_end
 
    # Add stack size to get usable stack pointer

    addi    $8, $8, (ESAL_AR_STK_STARTUP_SIZE)
    
    # Align the stack pointer as required.

    srl    $8, $8, ESAL_AR_STK_ALIGNMENT_OFFSET
    sll    $sp, $8, ESAL_AR_STK_ALIGNMENT_OFFSET

    # Jump to toolset run-time environment setup function.
    # NOTE:   control will not return here.

    j       ESAL_TS_RTE_Lowlevel_Initialize
    nop



#************************************************************************
#*
#*   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)

    .global ESAL_TS_RTE_Lowlevel_Initialize
ESAL_TS_RTE_Lowlevel_Initialize:

    # Initialize the Global Pointer ($gp).  This is used to maintain a base
    # pointer into a 64K global data area.  It does not change and therefore
    # is not part of a thread's context. The linker defines the value for _gp.

    la      $gp, _gp                        # Build the value of GP 
                                            # before any static data 
                                            # references are made 

    # Zero out the return register (r31) to provide 
    # a nicer debug environment (call stack-trace)

    add     $31, $0, $0

    # Call OS entry point

    j      OS_Init_Entry
    nop



#************************************************************************
#*
#*  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)

# RIZ    .code 32 # ESAL_TS_STK_Solicited_Restore
# RIZ    .global ESAL_TS_STK_Solicited_Restore
# RIZ    .type ESAL_TS_STK_Solicited_Restore, %function
    .global ESAL_TS_STK_Solicited_Restore
ESAL_TS_STK_Solicited_Restore:

    # Switch to the stack pointer passed-in

    add       $sp, $0, $4

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

    lw        $16, 4 ($sp)
    lw        $17, 8 ($sp) 
    lw        $18, 12($sp)
    lw        $19, 16($sp)
    lw        $20, 20($sp)
    lw        $21, 24($sp)
    lw        $22, 28($sp)
    lw        $23, 32($sp)
    lw        $30, 36($sp)

    # Get return address from stack frame

    lw        $31, 40($sp)

.if ESAL_AR_STK_FPU_SUPPORT

    lwc1      $f20, 40($sp)
    lwc1      $f21, 44($sp)
    lwc1      $f22, 48($sp)
    lwc1      $f23, 52($sp)
    lwc1      $f24, 56($sp)
    lwc1      $f25, 60($sp)
    lwc1      $f26, 64($sp)
    lwc1      $f27, 68($sp)
    lwc1      $f28, 72($sp)
    lwc1      $f29, 76($sp)
    lwc1      $f30, 80($sp)
    lwc1      $f31, 84($sp)

.endif

    # return to caller

    jr        $31

    # Return stack space (delay slot)

    addi   $sp, $sp, ESAL_TS_STK_FRAME_SIZE



#************************************************************************
#*
#*  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)

    .global ESAL_TS_STK_Solicited_Switch
ESAL_TS_STK_Solicited_Switch:

    # Save the toolset required registers to the current stack.  

    addi        $sp, $sp, -(ESAL_TS_STK_FRAME_SIZE)
    sw          $16, 4($sp)
    sw          $17, 8($sp)
    sw          $18, 12($sp)
    sw          $19, 16($sp)
    sw          $20, 20($sp)
    sw          $21, 24($sp)
    sw          $22, 28($sp)
    sw          $23, 32($sp)
    sw          $30, 36($sp)
    sw          $31, 40($sp)

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

    sw          $0, 0($sp)

.if ESAL_AR_STK_FPU_SUPPORT

    # Saving FPU registers

    swc1        $f20, 40($sp)
    swc1        $f21, 44($sp)
    swc1        $f22, 48($sp)
    swc1        $f23, 52($sp)
    swc1        $f24, 56($sp)
    swc1        $f25, 60($sp)
    swc1        $f26, 64($sp)
    swc1        $f27, 68($sp)
    swc1        $f28, 72($sp)
    swc1        $f29, 76($sp)
    swc1        $f30, 80($sp)
    swc1        $f31, 84($sp)

.endif

    # Save resultant stack pointer to location passed in (delay slot)

    sw          $sp, 0($6)

    # Switch to the system stack

    la          $8, ESAL_GE_STK_System_SP
    lw          $sp, 0($8)
    
    # Jump to call-back function ($5)

    jr          $5
    nop



#************************************************************************
#*
#*  FUNCTION
#*
#*      ESAL_AR_ISR_General_Exception_Handler
#*
#*  DESCRIPTION
#*
#*      This is the handler for all MIPS exceptions.
#*
#*  CALLED BY
#*
#*      Interrupt / Exception Vector Table
#*
#*  CALLS
#*
#*      Registered Exception Handler
#*
#*  INPUTS
#*
#*      None
#*
#*  OUTPUTS
#*
#*      None
#*
#************************************************************************
#static  VOID    ESAL_AR_ISR_General_Exception_Handler(VOID)

    .global ESAL_AR_ISR_General_Exception_Handler
ESAL_AR_ISR_General_Exception_Handler:

    # Save minimum registers

    ESAL_AR_STK_MIN_SAVE

    # Get and isolate execption code and put in first parameter register.

    mfc0    $4, $13
    srl     $4, $4, 2
    andi    $4, $4, ESAL_AR_ISR_CR_EXCCODE_MASK
    addi    $4, $4, -1

    # Get exception handler dispatch table address.

    la      $8, ESAL_GE_ISR_Exception_Handler

    # Get exception handler address from table.

    sll     $5, $4, 2
    add     $8, $5, $8
    lw      $8, 0($8)

    # Jump to exception handler

    jal     $8

    # Pass stack pointer in second param (delay slot)

    or      $5, $0, $sp

    # Restore all stack registers 

    ESAL_AR_STK_MIN_RESTORE

    # Return to point of Exception

    eret

#************************************************************************
#*
#*  FUNCTION
#*
#       ESAL_AR_ISR_Special_Interrupt_Handler
#*
#*  DESCRIPTION
#*
#*      Handler for all MIPS hardware and software interrupts.
#*
#*  CALLED BY
#*
#*      Interrupt / Exception Vector Table
#*
#*  CALLS
#*
#*      Registered Interrupt Handler
#*      ESAL_AR_STK_Unsolicited_Switch
#*                                                                      
#*  INPUTS
#*
#*      None
#*
#*  OUTPUTS
#*
#*      None
#*
#************************************************************************
#static  VOID    ESAL_AR_ISR_Special_Interrupt_Handler(VOID)

    .global ESAL_AR_ISR_Special_Interrupt_Handler
ESAL_AR_ISR_Special_Interrupt_Handler:

    # Code for ISR hook.  Registers saved will depend on
    # toolset and optimization level.

.if ESAL_AR_ISR_HOOK_ENABLED

    addi     $sp, $sp, -12

    # Save minimum registers

    sw       $2,  0($sp)
    sw       $3,  4($sp)
    sw       $31, 8($sp)

    # Jump to hook function

    jal    ESAL_AR_ISR_HOOK
    nop

    # Restore minimum registers

    lw       $2,  0($sp)
    lw       $3,  4($sp)
    lw       $31, 8($sp)

    # re-adjust stack pointer

    addi     $sp, $sp, 12

.endif

    # Save minimum registers

    ESAL_AR_STK_MIN_SAVE

    # Move stack pointer into second param

    or     $5, $0, $sp

    # Get current interrupt execution status

    la     $8, ESAL_GE_ISR_Executing
    lw     $8, 0($8)

    # Check if it is a nested interrupt

    bne    $0, $8, ESAL_AR_ISR_OS_Nested_Entry
    nop

    # Switch to system stack

    la     $8, ESAL_GE_STK_System_SP
    lw     $sp, 0($8)

    # Interrupt is not nested call non-nested interrupt handler

    la     $8, ESAL_GE_ISR_OS_Entry
    lw     $8, 0($8)
    jal    $8

    # Load special vector number (0) into first param (delay slot)

    li     $4, 0

    # Get Unsolicited stack switch flag

    la     $8, ESAL_GE_STK_Unsol_Switch_Req
    lw     $8, 0($8)

    # Check if context switch is required

    bne    $8, $0, ESAL_AR_ISR_Unsolicited_Switch
    nop

    # Restore original stack
    # NOTE: There was a stack switch in the function call.
    #       The correct stack pointer is being returned.

    lw     $sp, 0($2)

    # Restore all stack registers

    ESAL_AR_STK_MIN_RESTORE

    # Return to point of interrupt

    eret

ESAL_AR_ISR_Unsolicited_Switch:

    # Jump to Unsolicited switch.

    j   ESAL_AR_STK_Unsolicited_Switch
    nop

ESAL_AR_ISR_OS_Nested_Entry:

    # Adjust stack pointer for MIPS32 ABI.

    addi   $sp, $sp, -16

    # Interrupt is nested - call nested interrupt handler

    la     $8, ESAL_GE_ISR_OS_Nested_Entry
    lw     $8, 0($8)
    jal    $8

    # Load vector number (0) into first param (delay slot)

    li     $4, 0

    # Reset stack pointer to original value.
    
    addi   $sp, $sp, 16
    
    # Restore all stack registers

    ESAL_AR_STK_MIN_RESTORE

    # Return to point of interrupt

    eret


