/************************************************************************
 *
 *             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_ppc.S
 *
 *  DESCRIPTION
 *
 *      This file contains the base PPC 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
 *      ESAL_AR_ISR_External_Handler
 *      ESAL_AR_ISR_Critical_Handler
 *      ESAL_AR_ISR_Nested_Crit_ISR
 *      ESAL_AR_ISR_Exception_Handler
 *      ESAL_Get_Current_TLB
 *      ESAL_Create_Temp_TLB_Entry
 *      ESAL_Switch_Address_Space
 *
 *  DEPENDENCIES
 *
 *      nucleus_gen_cfg.h
 *      csgnu_ppc_defs.inc
 *
 *************************************************************************/

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

    #include    "nucleus_gen_cfg.h"
    #include    "csgnu_ppc_defs.inc"

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

#**********************************
#* EXTERNAL VARIABLE DECLARATIONS *
#**********************************

# 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 VOID    *ESAL_GE_STK_System_SP;
# extern INT     ESAL_GE_STK_Unsol_Switch_Req;

    .extern ESAL_GE_ISR_OS_Entry
    .extern ESAL_GE_ISR_OS_Nested_Entry
    .extern ESAL_GE_ISR_Exception_Handler
    .extern ESAL_GE_ISR_Executing
    .extern ESAL_GE_STK_System_SP
    .extern ESAL_GE_STK_Unsol_Switch_Req
#if (CFG_NU_OS_SVCS_TRACE_CORE_PC_HOTSPOT_SUPPORT == 1)
    .extern Trace_PC_Sample
#endif
    
# Import linker produced labels

    .extern     _ld_bss_end
    .extern     _ld_ram_sdata_start
    .extern     _ld_ram_sdata2_start

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

# extern VOID    ESAL_AR_STK_Startup_SP_Set(VOID);

    .extern ESAL_AR_STK_Startup_SP_Set

#****************************
#* FUNCTION DECLARATIONS    *
#****************************
    
    .section    esal_code, "ax"
    .align      4
    
#*************************************
#* EXTERNAL VARIABLE DECLARATIONS    *
#*************************************
    
    .extern ESAL_GE_MEM_ROM_Support_Enabled

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

    .weak   Board_Lowlevel_Init
Board_Lowlevel_Init:

    # Return to caller

    blr

#************************************************************************
#*
#*   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)
    
    li      r0,0

    addis   r3,0,ESAL_GE_MEM_ROM_Support_Enabled@ha
    lwz     r3,ESAL_GE_MEM_ROM_Support_Enabled@l(r3)
    cmpli   0, r3, 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:

    # Branch 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
#*
#*       stack_ptr                           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 new stack

    mr      r1,r3

#if (CFG_NU_OS_ARCH_PPC_COM_SPE_SUPPORT == 1)

    # If we are in SPE mode, the general registers are 8-byte registers.
    # Because of this, the restore macro below will adjust the current SP by 8
    # since it assumes it is currently pointing to an 8-byte value. But it isn't.
    # SP is currently pointing at the stack type which is a 4=byte value.
    # In order to adjust for the macro, we move the SP back 4-bytes so that
    # when the macro adds 8, it will be pointing past the 4-byte stack type.
    addi    r1,r1,-4 # Adjust stack so restore macro aligns for SPE mode

#endif

    # Restore r14 - r31 from stack

    ESAL_AR_RESTORE_REGISTER r14
    ESAL_AR_RESTORE_REGISTER r15
    ESAL_AR_RESTORE_REGISTER r16
    ESAL_AR_RESTORE_REGISTER r17
    ESAL_AR_RESTORE_REGISTER r18
    ESAL_AR_RESTORE_REGISTER r19
    ESAL_AR_RESTORE_REGISTER r20
    ESAL_AR_RESTORE_REGISTER r21
    ESAL_AR_RESTORE_REGISTER r22
    ESAL_AR_RESTORE_REGISTER r23
    ESAL_AR_RESTORE_REGISTER r24
    ESAL_AR_RESTORE_REGISTER r25
    ESAL_AR_RESTORE_REGISTER r26
    ESAL_AR_RESTORE_REGISTER r27
    ESAL_AR_RESTORE_REGISTER r28
    ESAL_AR_RESTORE_REGISTER r29
    ESAL_AR_RESTORE_REGISTER r30
    ESAL_AR_RESTORE_REGISTER r31

#if (CFG_NU_OS_ARCH_PPC_COM_SPE_SUPPORT == 0)

    # Adjust sp for last "pop" from stack
    addi    r1,r1,4

#else /* CFG_NU_OS_ARCH_PPC_COM_SPE_SUPPORT == 1) */

    # Adjust sp for last "pop" from stack
    addi    r1,r1,8

#endif /* CFG_NU_OS_ARCH_PPC_COM_SPE_SUPPORT == 0 */

#if (CFG_NU_OS_ARCH_PPC_COM_FPU_SUPPORT == 1)

    # Restore all FPU registers

    lfdu    f0,0(r1)
    mtfsf   ESAL_AR_STK_FPSCR_FM,f0
    lfdu    f0,8(r1)
    lfdu    f1,8(r1)
    lfdu    f2,8(r1)
    lfdu    f3,8(r1)
    lfdu    f4,8(r1)
    lfdu    f5,8(r1)
    lfdu    f6,8(r1)
    lfdu    f7,8(r1)
    lfdu    f8,8(r1)
    lfdu    f9,8(r1)
    lfdu    f10,8(r1)
    lfdu    f11,8(r1)
    lfdu    f12,8(r1)
    lfdu    f13,8(r1)
    lfdu    f14,8(r1)
    lfdu    f15,8(r1)
    lfdu    f16,8(r1)
    lfdu    f17,8(r1)
    lfdu    f18,8(r1)
    lfdu    f19,8(r1)
    lfdu    f20,8(r1)
    lfdu    f21,8(r1)
    lfdu    f22,8(r1)
    lfdu    f23,8(r1)
    lfdu    f24,8(r1)
    lfdu    f25,8(r1)
    lfdu    f26,8(r1)
    lfdu    f27,8(r1)
    lfdu    f28,8(r1)
    lfdu    f29,8(r1)
    lfdu    f30,8(r1)
    lfdu    f31,8(r1)

    # Adjust sp for last "pop" from stack
    addi    r1,r1,8

#endif

    # Restore remaining registers and return from interrupt

    ESAL_AR_STK_MIN_RESTORE

    # Return to point of interrupt

    rfi


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

    lwz     r1,0(r3)

    # Save the remaining context to this stack

#if (CFG_NU_OS_ARCH_PPC_COM_FPU_SUPPORT == 1)

    # Save all FPU registers

    stfdu   f31,-8(r1)
    stfdu   f30,-8(r1)
    stfdu   f29,-8(r1)
    stfdu   f28,-8(r1)
    stfdu   f27,-8(r1)
    stfdu   f26,-8(r1)
    stfdu   f25,-8(r1)
    stfdu   f24,-8(r1)
    stfdu   f23,-8(r1)
    stfdu   f22,-8(r1)
    stfdu   f21,-8(r1)
    stfdu   f20,-8(r1)
    stfdu   f19,-8(r1)
    stfdu   f18,-8(r1)
    stfdu   f17,-8(r1)
    stfdu   f16,-8(r1)
    stfdu   f15,-8(r1)
    stfdu   f14,-8(r1)
    stfdu   f13,-8(r1)
    stfdu   f12,-8(r1)
    stfdu   f11,-8(r1)
    stfdu   f10,-8(r1)
    stfdu   f9,-8(r1)
    stfdu   f8,-8(r1)
    stfdu   f7,-8(r1)
    stfdu   f6,-8(r1)
    stfdu   f5,-8(r1)
    stfdu   f4,-8(r1)
    stfdu   f3,-8(r1)
    stfdu   f2,-8(r1)
    stfdu   f1,-8(r1)
    stfdu   f0,-8(r1)
    mffs    f0
    stfdu   f0,-8(r1)

#endif

    #  Save remaining general purpose registers.

    ESAL_AR_SAVE_REGISTER r31
    ESAL_AR_SAVE_REGISTER r30
    ESAL_AR_SAVE_REGISTER r29
    ESAL_AR_SAVE_REGISTER r28
    ESAL_AR_SAVE_REGISTER r27
    ESAL_AR_SAVE_REGISTER r26
    ESAL_AR_SAVE_REGISTER r25
    ESAL_AR_SAVE_REGISTER r24
    ESAL_AR_SAVE_REGISTER r23
    ESAL_AR_SAVE_REGISTER r22
    ESAL_AR_SAVE_REGISTER r21
    ESAL_AR_SAVE_REGISTER r20
    ESAL_AR_SAVE_REGISTER r19
    ESAL_AR_SAVE_REGISTER r18
    ESAL_AR_SAVE_REGISTER r17
    ESAL_AR_SAVE_REGISTER r16
    ESAL_AR_SAVE_REGISTER r15
    ESAL_AR_SAVE_REGISTER r14

    # Save stack type on top of stack (1 = unsolicited stack frame)

    li      r12,1
    stwu    r12,-4(r1)

    # Save new stack pointer back into passed-in stack pointer address

    stw     r1,0(r3)

    # Switch to the system stack

    addis   r10,0,ESAL_GE_STK_System_SP@ha
    lwz     r1,ESAL_GE_STK_System_SP@l(r10)

    # Clear switch flag

    li      r3,0
    addis   r10,0,ESAL_GE_STK_Unsol_Switch_Req@ha
    stw     r3,ESAL_GE_STK_Unsol_Switch_Req@l(r10)

    # Get address of OS switch function

    addis   r10,0,ESAL_GE_STK_Unsol_Switch_OS_Entry@ha
    lwz     r10,ESAL_GE_STK_Unsol_Switch_OS_Entry@l(r10)

    # Jump to OS switch function

    mtspr   CTR,r10
    bcctr   ESAL_AR_STK_BRANCH_ALWAYS,0


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

ESAL_AR_STK_BSS_End:
        .long _ld_bss_end
    
#************************************************************************
#*
#*  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:

#if (CFG_NU_OS_ARCH_PPC_COM_SPE_SUPPORT == 1) || (CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 1)

    # Enable SPE support if user requires or if this is a BookE variant

    mfmsr   r3
    oris    r3,r3,0x200
    mtmsr   r3

#endif

#if (CFG_NU_OS_ARCH_PPC_COM_FPU_SUPPORT == 1)

    # Enable FPU if available

    mfmsr   r3
    ori     r3,r3,ESAL_AR_STK_MSR_FP
    mtmsr   r3

#endif

    # Get end address of BSS for stack pointer

    addis   r1,0,ESAL_AR_STK_BSS_End@ha
    lwz     r1,ESAL_AR_STK_BSS_End@l(r1)

    # Add startup stack size

    li      r4,ESAL_AR_STK_STARTUP_SIZE@l
    add     r1,r1,r4

    # Align stack pointer to correct boundary

    li      r4,ESAL_AR_STK_ALIGNMENT_SHIFT
    srw     r1,r1,r4
    slw     r1,r1,r4

    # After stack pointer is set, jump to toolset run-time environment
    # setup function */

    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)

    .global ESAL_TS_RTE_Lowlevel_Initialize
ESAL_TS_RTE_Lowlevel_Initialize:

    # Load r13 with small-data area base addresses produced by the linker

    lis     r13,_ld_ram_sdata_start@h
    ori     r13,r13,_ld_ram_sdata_start@l

    # Load r2 with small-data area 2 base addresses produced by the linker

    lis     r2,_ld_ram_sdata2_start@h
    ori     r2,r2,_ld_ram_sdata2_start@l

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

    li      r10,0
    mtspr   LR,r10

    # Branch to the OS entry point

    b      OS_Init_Entry

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

    .global ESAL_TS_STK_Solicited_Restore
ESAL_TS_STK_Solicited_Restore:

    # Switch to the stack passed into this function

    mr      r1,r3

#if (CFG_NU_OS_ARCH_PPC_COM_SPE_SUPPORT == 1)

    # If we are in SPE mode, the general registers are 8-byte registers.
    # Because of this, the restore macro below will adjust the current SP by 8
    # since it assumes it is currently pointing to an 8-byte value. But it isn't.
    # SP is currently pointing at the stack type which is a 4=byte value.
    # In order to adjust for the macro, we move the SP back 4-bytes so that
    # when the macro adds 8, it will be pointing past the 4-byte stack type.
    addi    r1,r1,-4

#endif

    # Restore context of solicited stack frame (skipping stack type)

    ESAL_AR_RESTORE_REGISTER r14
    ESAL_AR_RESTORE_REGISTER r15
    ESAL_AR_RESTORE_REGISTER r16
    ESAL_AR_RESTORE_REGISTER r17
    ESAL_AR_RESTORE_REGISTER r18
    ESAL_AR_RESTORE_REGISTER r19
    ESAL_AR_RESTORE_REGISTER r20
    ESAL_AR_RESTORE_REGISTER r21
    ESAL_AR_RESTORE_REGISTER r22
    ESAL_AR_RESTORE_REGISTER r23
    ESAL_AR_RESTORE_REGISTER r24
    ESAL_AR_RESTORE_REGISTER r25
    ESAL_AR_RESTORE_REGISTER r26
    ESAL_AR_RESTORE_REGISTER r27
    ESAL_AR_RESTORE_REGISTER r28
    ESAL_AR_RESTORE_REGISTER r29
    ESAL_AR_RESTORE_REGISTER r30
    ESAL_AR_RESTORE_REGISTER r31

#if (CFG_NU_OS_ARCH_PPC_COM_SPE_SUPPORT == 0)

    # Adjust sp for last "pop" from stack
    addi    r1,r1,4

#else /* CFG_NO_OS_ARCH_PPC_COM_SPE_SUPPORT == 1) */

    # Adjust sp for last "pop" from stack
    addi    r1,r1,8

#endif /* CFG_NO_OS_ARCH_PPC_COM_SPE_SUPPORT == 0) */

    # Restore CTR, CR and LR registers

    lwzu    r3,0(r1)
    mtspr   CTR,r3
    lwzu    r3,4(r1)
    mtcr    r3
    lwzu    r3,4(r1)
    mtspr   LR,r3

    # Adjust sp for last "pop" from stack
    addi    r1,r1,4

#if (CFG_NU_OS_ARCH_PPC_COM_FPU_SUPPORT == 1)

    lfdu    f14,0(r1)
    lfdu    f15,8(r1)
    lfdu    f16,8(r1)
    lfdu    f17,8(r1)
    lfdu    f18,8(r1)
    lfdu    f19,8(r1)
    lfdu    f20,8(r1)
    lfdu    f21,8(r1)
    lfdu    f22,8(r1)
    lfdu    f23,8(r1)
    lfdu    f24,8(r1)
    lfdu    f25,8(r1)
    lfdu    f26,8(r1)
    lfdu    f27,8(r1)
    lfdu    f28,8(r1)
    lfdu    f29,8(r1)
    lfdu    f30,8(r1)
    lfdu    f31,8(r1)

    # Adjust sp for last "pop" from stack
    addi    r1,r1,8

#endif

    # Return to caller

    blr


#************************************************************************
#*
#*  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 a solicited stack frame

#if (CFG_NU_OS_ARCH_PPC_COM_FPU_SUPPORT == 1)

    # Save all FPU registers

    stfdu   f31,-8(r1)
    stfdu   f30,-8(r1)
    stfdu   f29,-8(r1)
    stfdu   f28,-8(r1)
    stfdu   f27,-8(r1)
    stfdu   f26,-8(r1)
    stfdu   f25,-8(r1)
    stfdu   f24,-8(r1)
    stfdu   f23,-8(r1)
    stfdu   f22,-8(r1)
    stfdu   f21,-8(r1)
    stfdu   f20,-8(r1)
    stfdu   f19,-8(r1)
    stfdu   f18,-8(r1)
    stfdu   f17,-8(r1)
    stfdu   f16,-8(r1)
    stfdu   f15,-8(r1)
    stfdu   f14,-8(r1)

#endif

    #  Save LR, CR and CTR registers

    mfspr   r10,LR
    stwu    r10,-4(r1)
    mfcr    r10
    stwu    r10,-4(r1)
    mfspr   r10,CTR
    stwu    r10,-4(r1)

    #  Save remaining general purpose registers.

    ESAL_AR_SAVE_REGISTER r31
    ESAL_AR_SAVE_REGISTER r30
    ESAL_AR_SAVE_REGISTER r29
    ESAL_AR_SAVE_REGISTER r28
    ESAL_AR_SAVE_REGISTER r27
    ESAL_AR_SAVE_REGISTER r26
    ESAL_AR_SAVE_REGISTER r25
    ESAL_AR_SAVE_REGISTER r24
    ESAL_AR_SAVE_REGISTER r23
    ESAL_AR_SAVE_REGISTER r22
    ESAL_AR_SAVE_REGISTER r21
    ESAL_AR_SAVE_REGISTER r20
    ESAL_AR_SAVE_REGISTER r19
    ESAL_AR_SAVE_REGISTER r18
    ESAL_AR_SAVE_REGISTER r17
    ESAL_AR_SAVE_REGISTER r16
    ESAL_AR_SAVE_REGISTER r15
    ESAL_AR_SAVE_REGISTER r14

    # Save stack type (0 = solicited stack frame)

    li      r10,0
    stwu    r10,-4(r1)

    # Save stack pointer to specified location

    stw     r1,0(r5)

    # Switch to the system stack

    addis   r10,0,ESAL_GE_STK_System_SP@ha
    lwz     r1,ESAL_GE_STK_System_SP@l(r10)

    # Jump to call-back function

    mtspr   CTR,r4
    bcctr   ESAL_AR_STK_BRANCH_ALWAYS,0

#************************************************************************
#*
#*  FUNCTION
#*
#*      ESAL_AR_ISR_External_Handler
#*
#*  DESCRIPTION
#*
#*      This function handles all external interrupts for the
#*      architecture (machine check, external, and decrementer)
#*
#*  CALLED BY
#*
#*      Machine check, external, decrementer
#*
#*  CALLS
#*
#*      OS Interrupt handlers
#*
#*  INPUTS
#*
#*      r3 - vector number
#*
#*  OUTPUTS
#*
#*      None
#*
#************************************************************************
#VOID  ESAL_AR_ISR_External_Handler(INT vector)

    .global ESAL_AR_ISR_External_Handler
ESAL_AR_ISR_External_Handler:

    # Put current SP in second parameter register (r4)
    # (vector is in first parameter register - r3)

    mr      r4,r1

#if (CFG_NU_OS_SVCS_TRACE_CORE_PC_HOTSPOT_SUPPORT == 1)

    # Get interrupt return address and store it in Trace_PC_Sample

    addis   r12,0,Trace_PC_Sample@ha
    lwzu    r11,ESAL_AR_STK_MIN_LR_OFFSET(r1)
    stw     r11,Trace_PC_Sample@l(r12)

#endif

    # Get flag to show if ISR is executing already

    addis   r12,0,ESAL_GE_ISR_Executing@ha
    lwz     r12,ESAL_GE_ISR_Executing@l(r12)

    # Check if an interrupt is currently executing

    cmpli   0,r12,0
    bne     ESAL_AR_ISR_Nested_ISR

    # First ISR, switch to the system stack

    addis   r12,0,ESAL_GE_STK_System_SP@ha
    lwz     r1,ESAL_GE_STK_System_SP@l(r12)

    # Get OS non-nested ISR function pointer

    addis   r12,0,ESAL_GE_ISR_OS_Entry@ha
    lwz     r12,ESAL_GE_ISR_OS_Entry@l(r12)

    # Call OS non-nested ISR function

    mtspr   CTR,r12
    bcctrl  ESAL_AR_STK_BRANCH_ALWAYS,0

    # Get value of flag used to show if context switch is required

    addis   r12,0,ESAL_GE_STK_Unsol_Switch_Req@ha
    lwz     r12,ESAL_GE_STK_Unsol_Switch_Req@l(r12)

    # Branch to unsolicited switch if required

    cmpli   0,r12,1
    beq     ESAL_AR_STK_Unsolicited_Switch

    # No switch is required, restore stack pointer (pointer to stack pointer returned in r3)

    lwz     r1,0(r3)

    # Restore minimum context

    ESAL_AR_STK_MIN_RESTORE

    # Return to point of interrupt

    rfi

ESAL_AR_ISR_Nested_ISR:

    # Get OS nested ISR function pointer

    addis   r12,0,ESAL_GE_ISR_OS_Nested_Entry@ha
    lwz     r12,ESAL_GE_ISR_OS_Nested_Entry@l(r12)

    # Adjust sp for PPC EABI

#if (CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0)
# PPC32 variant ONLY

    # NOTE: 17 registers (68 bytes) saved on stack - this subtraction
    #       creates a 16-byte aligned stack pointer

    addi    r1,r1,-12

#else /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 1 */
# BookE variant ONLY

    addi    r1,r1,-16

#endif /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0 */

    # Call OS non-nested ISR function

    mtspr   CTR,r12
    bcctrl  ESAL_AR_STK_BRANCH_ALWAYS,0

    # Restore sp change for PPC EABI

#if (CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0)
# PPC32 variant ONLY

    addi    r1,r1,12

#else /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 1 */
# BookE variant ONLY

    addi    r1,r1,16

#endif /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0 */

    # Restore minimum context and return from interrupt

    ESAL_AR_STK_MIN_RESTORE

    # Return to point of interrupt

    rfi


#if (CFG_NU_OS_ARCH_PPC_COM_CRIT_INT_SUPPORT == 1)
#************************************************************************
#*
#*  FUNCTION
#*
#*      ESAL_AR_ISR_Critical_Handler
#*
#*  DESCRIPTION
#*
#*      This function handles critical interrupts
#*
#*  CALLED BY
#*
#*      Critical interrupts
#*
#*  CALLS
#*
#*      None
#*
#*  INPUTS
#*
#*      r3 - vector number
#*
#*  OUTPUTS
#*
#*      None
#*
#************************************************************************
#VOID  ESAL_AR_ISR_Critcal_Handler(INT vector)

    .global ESAL_AR_ISR_Critical_Handler
ESAL_AR_ISR_Critical_Handler:

    # Put current SP in second parameter register (r4)
    # (vector is in first parameter register - r3)

    mr      r4,r1

#if (CFG_NU_OS_SVCS_TRACE_CORE_PC_HOTSPOT_SUPPORT == 1)

    # Get interrupt return address and store it in Trace_PC_Sample

    addis   r12,0,Trace_PC_Sample@ha
    lwzu    r11,ESAL_AR_STK_MIN_LR_OFFSET(r1)
    stw     r11,Trace_PC_Sample@l(r12)

#endif

    # Get flag to show if ISR is executing already

    addis   r12,0,ESAL_GE_ISR_Executing@ha
    lwz     r12,ESAL_GE_ISR_Executing@l(r12)

    # Check if an interrupt is currently executing

    cmpli   0,r12,0
    bne     ESAL_AR_ISR_Nested_Crit_ISR

    # First ISR - switch to the system stack

    addis   r12,0,ESAL_GE_STK_System_SP@ha
    lwz     r1,ESAL_GE_STK_System_SP@l(r12)

    # Get OS non-nested ISR function pointer

    addis   r12,0,ESAL_GE_ISR_OS_Entry@ha
    lwz     r12,ESAL_GE_ISR_OS_Entry@l(r12)

    # Call OS non-nested ISR function

    mtspr   CTR,r12
    bcctrl  ESAL_AR_STK_BRANCH_ALWAYS,0

    # Get value of flag used to show if context switch is required

    addis   r12,0,ESAL_GE_STK_Unsol_Switch_Req@ha
    lwz     r12,ESAL_GE_STK_Unsol_Switch_Req@l(r12)

    # Branch to unsolicited switch if required

    cmpli   0,r12,1
    beq     ESAL_AR_STK_Unsolicited_Switch

    # No switch is required, restore stack pointer (pointer to stack pointer returned in r3)

    lwz     r1,0(r3)

    # Restore minimum context, along with CSRR0 and CSRR1, and return from interrupt

    ESAL_AR_STK_MIN_RESTORE ESAL_AR_ISR_CSRR0_NUM,ESAL_AR_ISR_CSRR1_NUM

    # Return to point of interrupt

    rfci

    .global ESAL_AR_ISR_Nested_Crit_ISR
ESAL_AR_ISR_Nested_Crit_ISR:

    # Get OS nested ISR function pointer

    addis   r12,0,ESAL_GE_ISR_OS_Nested_Entry@ha
    lwz     r12,ESAL_GE_ISR_OS_Nested_Entry@l(r12)

    # Adjust sp for PPC EABI

#if (CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0)
# PPC32 variant ONLY

    # NOTE: 17 registers (68 bytes) saved on stack - this subtraction
    #       creates a 16-byte aligned stack pointer

    addi    r1,r1,-12

#else /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 1 */
# BookE variant ONLY

    addi    r1,r1,-16

#endif /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0 */

    # Call OS nested ISR function

    mtspr   CTR,r12
    bcctrl  ESAL_AR_STK_BRANCH_ALWAYS,0

    # Restore sp change for PPC EABI

#if (CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0)
# PPC32 variant ONLY

    addi    r1,r1,12

#else /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 1 */
# BookE variant ONLY

    addi    r1,r1,16

#endif /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0 */

    # Restore minimum context, along with CSRR0 and CSRR1, and return from interrupt

    ESAL_AR_STK_MIN_RESTORE ESAL_AR_ISR_CSRR0_NUM,ESAL_AR_ISR_CSRR1_NUM

    # Return to point of interrupt

    rfci

#endif


#************************************************************************
#*
#*  FUNCTION
#*
#*      ESAL_AR_ISR_Exception_Handler
#*
#*  DESCRIPTION
#*
#*      This function is the main architecture exception handler
#*
#*  CALLED BY
#*
#*      all exceptions
#*
#*  CALLS
#*
#*      None
#*
#*  INPUTS
#*
#*      r3 - vector number
#*
#*  OUTPUTS
#*
#*      None
#*
#************************************************************************
#VOID  ESAL_AR_ISR_Exception_Handler(INT vector)

    .global ESAL_AR_ISR_Exception_Handler
ESAL_AR_ISR_Exception_Handler:

    # Put current SP in second parameter register (r4)
    # (vector is in first parameter register - r3)

    mr      r4,r1

    # Get address of exception handler dispatch table

    lis     r12,ESAL_GE_ISR_Exception_Handler@h
    ori     r12,r12,ESAL_GE_ISR_Exception_Handler@l

    # Multiply the exception vector by 4 to get offset into the dispatch table

    mulli   r10,r3,4

    # Load the exception handler address from the dispatch table

    lwzx    r12,r12,r10

#if (CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0)
# PPC32 variant ONLY

    # Adjust sp for PPC EABI
    # NOTE: 17 registers (68 bytes) saved on stack - this subtraction
    #       creates a 16-byte aligned stack pointer

    addi    r1,r1,-12

#else /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 1 */
# BookE variant ONLY

    addi    r1,r1,-16

#endif /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0 */

    # Call OS non-nested ISR function

    mtspr   CTR,r12
    bcctrl  ESAL_AR_STK_BRANCH_ALWAYS,0

    # Restore sp change for PPC EABI

#if (CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0)
# PPC32 variant ONLY

    addi    r1,r1,12

#else /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 1 */
# BookE variant ONLY

    addi    r1,r1,16

#endif /* CFG_NU_OS_ARCH_PPC_COM_PPC_VARIANT == 0 */

    # Restore minimum context

    ESAL_AR_STK_MIN_RESTORE

    # Return to point of exception

    rfi

#************************************************************************
#*
#*  FUNCTION
#*
#*      ESAL_Get_Current_TLB
#*
#*  DESCRIPTION
#*
#*      This function performs the following actions
#*
#*      1. Obtain Nucleus load address
#*      2. Identify and protect current TLB1 entry being used by Nucleus
#*
#*  CALLED BY
#*
#*      ESAL_CO_MEM_Cache_Enable
#*
#*  CALLS
#*
#*      None
#*
#*  INPUTS
#*
#*      None
#*
#*  OUTPUTS
#*
#*      Number of the TLB currently being used by the executing code
#*
#************************************************************************
#UINT32 ESAL_Get_Current_TLB(VOID)

    .global ESAL_Get_Current_TLB
ESAL_Get_Current_TLB:

    /* Save Link Register in CTR register */
    mflr    r2
    mtspr   CTR,r2

    /* 1. Obtain Nucleus load address */
    li      r0,0            /* set r0 to 0 for assembler usage */
    bl      llbl0           /* to obtain current operating pc */
llbl0:
    mflr    r7
    rlwinm  r7,r7,0,0,11    /* mask for min supported boundary 1MB */

    /* 2. Identify and protect current TLB1 entry being used by Nucleus */
    mfmsr   r2              /* get current address space */
    rlwinm  r2,r2,27,31,31
    mfspr   r3,SPR_PID0     /* get current process id */
    rlwinm  r3,r3,0,22,31
    rlwinm  r3,r3,16,8,15
    or      r3,r3,r2
    mtspr   SPR_MAS6,r3     /* set up mas6 for tlb search */
    isync
    tlbsx   0,r7            /* tlb search */
    mfspr   r2,SPR_MAS1     /* check if we have a valid entry */
    andis.  r2,r2,MAS1_TLB1_VALID_BIT@h
    bne     match_found
    b       .               /* match not found!,pls implement error handling*/
match_found:
    mfspr   r2,SPR_MAS0
    rlwinm  r3,r2,16,20,31  /* extract MAS0(Entry) in r3 */
    mfspr   r2,SPR_MAS1     /* set IPROT bit in MAS1*/
    oris    r2,r2,MAS1_TLB1_IPROT_BIT@h
    mtspr   SPR_MAS1,r2
    isync

    isync
    tlbwe
    isync
    msync

    /* Return TLB entry number in r0 */
    mr      r0,r3

    /* Branch to caller */
    bctr

#************************************************************************
#*
#*  FUNCTION
#*
#*      ESAL_Create_Temp_TLB_Entry
#*
#*  DESCRIPTION
#*
#*      This function performs the following actions
#*
#*      1. Creates a temp TLB entry in address space 1
#*
#*  CALLED BY
#*
#*      ESAL_CO_MEM_Cache_Enable
#*
#*  CALLS
#*
#*      create_tlb_entry
#*
#*  INPUTS
#*
#*      tlb_entry_num
#*
#*  OUTPUTS
#*
#*      None
#*
#************************************************************************
#VOID ESAL_Create_Temp_TLB_Entry(UINT32 tlb_entry_num)

    .global ESAL_Create_Temp_TLB_Entry
ESAL_Create_Temp_TLB_Entry:

    /* Save Link Register in CTR register */
    mflr    r2
    mtspr   CTR,r2

    /* 1. Make a temp tlb entry in translation space 1 for nucleus */

    /* Program mas0 and read tlb entry */
    lis     r5,MAS0_TLB1_SELECT@h   /* set up MAS0 value */
    rlwimi  r5,r3,16,12,15          /* TLBSEL=1,ESEL=[r0]*/

    mtspr   SPR_MAS0,r5
    isync
    tlbre

    /* Program mas1 */
    lis     r2,MAS1_ENTRY_TS1_KERNEL_MAPPING@h      /* set up MAS1 entry */
    ori     r2,r2,MAS1_ENTRY_TS1_KERNEL_MAPPING@l   /* V=1,IPROT=1,TS=1,TSIZE=0x101(1MB)*/

    mtspr   SPR_MAS1,r2
    isync

    /* to obtain current operating pc */
    bl      llbl1
llbl1:
    mflr    r7
    rlwinm  r7,r7,0,0,11    /* mask for min supported boundary 1MB */

    /* Program mas2 */
    li      r3,0            /* clear out r3 */
    rlwimi  r3,r7,0,0,3     /* set up MAS2 entry */
    ori     r3,r3,0x08@l    /* EPN=[R7], WIMGE=0x08 */

    mtspr   SPR_MAS2,r3
    isync

    /* Program mas3 */
    li      r4,0            /* clear out r4 */
    rlwimi  r4,r7,0,0,3     /* set up MAS3 entry */
    ori     r4,r4,0x15@l    /* RPN=[R7], def vals for user/perm */

    mtspr   SPR_MAS3,r4
    isync

    /* Write TLB entry */
    isync
    tlbwe
    isync
    msync

    /* Branch to caller */
    bctr

#************************************************************************
#*
#*  FUNCTION
#*
#*      ESAL_Switch_Address_Space
#*
#*  DESCRIPTION
#*
#*      This function switches operating memory space to the requested
#*      address space (MSR[AS], and MSR[DS]) bits
#*
#*  CALLED BY
#*
#*      ESAL_CO_MEM_Cache_Enable
#*
#*  CALLS
#*
#*      none
#*
#*  INPUTS
#*
#*      address_space
#*
#*  OUTPUTS
#*
#*      None
#*
#************************************************************************
#VOID ESAL_Switch_Address_Space(INT address_space)

    .global ESAL_Switch_Address_Space
ESAL_Switch_Address_Space:

    /* Save Link Register in CTR register */
    mflr    r2
    mtspr   CTR,r2

    mfmsr   r2              /* read current MSR value */

    /* Determine address space we want to swtich to */
    cmpli   0,r3,0
    bne     space1

    /* 1. Switch to translation space 0 */
    li      r3,0x30
    andc    r2,r2,r3        /* clear IS and DS bits in MSR */
    b       llbl2

space1:
    /* 1. Switch to translation space 1 */
    ori     r2,r2,0x30      /* set IS and DS bits in MSR */

llbl2:
    bl      llbl3

llbl3:
    mflr    r3              /* obtain current address */

    addi    r3,r3,(resume2 - llbl3) /* calculate rfi return address */

    mtspr   SPR_SRR0,r3
    mtspr   SPR_SRR1,r2
    rfi                     /* rfi to switch address space */

resume2:
    /* Branch to caller */
    bctr

    .end

