/***********************************************************************
*
*             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
*
*       sh.c
*
*   DESCRIPTION
*
*       This file contains the core Renesas SuperH architecture functions
*
*   FUNCTIONS
*
*       ESAL_AR_STK_Unsolicited_Set
*       ESAL_TS_STK_Solicited_Set
*       ESAL_TS_MEM_First_Avail_Get
*       ESAL_TS_MEM_BSS_Clear
*       ESAL_TS_MEM_ROM_To_RAM_Copy
*       ESAL_AR_ISR_Initialize
*       ESAL_AR_ISR_Vector_Table_Install
*       ESAL_AR_ISR_Return
*       ESAL_GE_INT_Enable
*       ESAL_AR_INT_Disable
*       ESAL_AR_TMR_OS_Timer_Start
*       ESAL_CO_MEM_Cache_Enable
*
*   DEPENDENCIES
*
*       nucleus.h                 Contains system constants common to both the
*                                 application and the actual Nucleus PLUS components.
*       nu_kernel.h               Contains kernel constants common to both the
*                                 application and the actual Nucleus PLUS kernel.              
*
***********************************************************************/

/* Include required header files */
#include "nucleus.h"
#include "kernel/nu_kernel.h"

/* External variable declarations */
extern  VOID *                          ESAL_AR_ISR_Vector_Table;
                                           
/***********************************************************************
*
*   FUNCTION
*
*       ESAL_AR_STK_Unsolicited_Set
*
*   DESCRIPTION
*
*       This function populates a stack frame as required by the given
*       architecture (contains all registers that must be preserved
*       across an interrupt context switch).
*
*   CALLED BY
*
*       Operating System Services
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       start_addr                          Start address of stack mem
*       end_addr                            End address of stack mem
*       entry_function                      Address of execution entry
*
*   OUTPUTS
*
*       Stack Frame Stack Pointer
*
***********************************************************************/
VOID    *ESAL_AR_STK_Unsolicited_Set(VOID *start_addr, VOID *end_addr, 
                                     VOID (*entry_function)(VOID))
{
    NU_REG    ESAL_AR_STK     *stack_frame;

    /* Ensure unused parameter doesn't cause tool warnings */
    NU_UNUSED_PARAM(start_addr);

    /* Set address of interrupt stack frame */
    stack_frame = (ESAL_AR_STK *)((VOID_CAST)end_addr - ESAL_GE_STK_MAX_FRAME_SIZE);

    /* Set stack type within stack frame */
    stack_frame -> stack_type = ESAL_GE_STK_AR_TYPE;

    /* Set return address / entry point within stack frame */
    (stack_frame -> min_stack).rtn_address = (UINT32)entry_function;

    /* Zeroize pr within stack frame (allows nicer debugging environment - call stack terminated) */
    (stack_frame -> min_stack).pr = 0x00000000;

    /* Initialize SR to ensure interrupts are enabled on thread entry */
    (stack_frame -> min_stack).sr = ESAL_AR_INTERRUPTS_ENABLE_BITS;

#if (ESAL_AR_STK_FPU_SUPPORT == NU_TRUE)

    /* Initialize FPSCR register in stack frame */
    ESAL_TS_RTE_FPSCR_READ(&(stack_frame -> fpscr));

#endif  /* ESAL_AR_STK_FPU_SUPPORT */    

    /* Return stack pointer to caller */
    return ((VOID *)stack_frame);
}

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_TS_STK_Solicited_Set
*
*   DESCRIPTION
*
*       This function populates a solicited stack frame as required
*       by the toolset for this architecture.  A solicited stack
*       frame is one that contains all the registers required by
*       the given toolset to be preserved across a function call
*       boundary (i.e. registers that must be unchanged after making
*       a function call within C code).
*
*   CALLED BY
*
*       Operating System Services
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       start_addr                          Start address of stack mem
*       end_addr                            End address of stack mem
*       entry_function                      Address of exec. entry
*
*   OUTPUTS
*
*       Stack Frame Stack Pointer
*
***********************************************************************/
VOID    *ESAL_TS_STK_Solicited_Set(VOID *start_addr, VOID *end_addr,
                                   VOID (*entry_function)(VOID))
{
    NU_REG ESAL_TS_STK     *stack_frame;


    /* Ensure unused parameter doesn't cause tool warnings */
    NU_UNUSED_PARAM(start_addr);

    /* Set address of stack frame */
    stack_frame = (ESAL_TS_STK *)((UINT32)end_addr - ESAL_GE_STK_MIN_FRAME_SIZE);

    /* Set stack type within stack frame */
    stack_frame -> stack_type = ESAL_GE_STK_TS_TYPE;

    /* Set return address / entry point within stack frame */
    stack_frame -> rtn_address = (UINT32)entry_function;

    /* Return stack pointer to caller */
    return ((VOID *)stack_frame);
}

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_TS_MEM_First_Avail_Get
*
*   DESCRIPTION
*
*       This function returns the first available RAM memory address
*       available for use.  This value is usually obtained from
*       linker produced addresses and labels and it is a static value
*       (i.e. it won't be updated at run-time to reflect use of available
*       memory - it only represents the first available memory
*       address that existed at link time)
*
*   CALLED BY
*
*       ESAL_GE_MEM_Initialize
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       None
*
*   OUTPUTS
*
*       VOID *                              Pointer to first available
*                                           RAM memory usable
*
***********************************************************************/
VOID    *ESAL_TS_MEM_First_Avail_Get(VOID)
{
    /* Return the address of the first memory available for use
       by an application. */
    return (TOOLSET_BSS_END_ADDR);
}

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_TS_MEM_BSS_Clear
*
*   DESCRIPTION
*
*       This function clears the BSS for the given toolset
*
*   CALLED BY
*
*       ESAL_GE_RTE_Initialize
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       None
*
*   OUTPUTS
*
*       None
*
***********************************************************************/
VOID    ESAL_TS_MEM_BSS_Clear(VOID)
{
    /* Clear all BSS / Zero-initialized memory */
    ESAL_GE_MEM_Clear(TOOLSET_BSS_START_ADDR, TOOLSET_BSS_SIZE);
}

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_TS_MEM_ROM_To_RAM_Copy
*
*   DESCRIPTION
*
*       This function copies initialized data from ROM to RAM for the
*       given toolset
*
*   CALLED BY
*
*       ESAL_GE_RTE_Initialize
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       None
*
*   OUTPUTS
*
*       None
*
***********************************************************************/
VOID    ESAL_TS_MEM_ROM_To_RAM_Copy(VOID)
{
#if (( ESAL_GE_ROM_SUPPORT_ENABLED == NU_TRUE ) || ( ESAL_TS_ROM_TO_RAM_COPY_SUPPORT == NU_TRUE ))

    /* Check destination address (RAM data start) is not equal to 
       source address (ROM data start). */
    if (TOOLSET_DATA_DST_ADDR != TOOLSET_DATA_SRC_ADDR)
    {
        /* Copy initialized data from ROM to RAM */
        ESAL_GE_MEM_Copy(TOOLSET_DATA_DST_ADDR, TOOLSET_DATA_SRC_ADDR, TOOLSET_DATA_SIZE);
    }

#endif
}

#if (ESAL_AR_ISR_INIT_REQUIRED == NU_TRUE)

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_AR_ISR_Initialize
*
*   DESCRIPTION
*
*       This function performs any interrupt servicing related 
*       initialization  necessary for the given architecture.  
*       This includes setting-up interrupt related stacks, initializing
*       data used during interrupt handling, etc
*
*   CALLED BY
*
*       ESAL_GE_ISR_Initialize
*
*   CALLS
*   
*       None
*
*   INPUTS
*
*       None
*
*   OUTPUTS
*
*       None
*
***********************************************************************/
VOID    ESAL_AR_ISR_Initialize(VOID)
{
}

#endif /* ESAL_AR_ISR_INIT_REQUIRED */

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_AR_ISR_Vector_Table_Install
*
*   DESCRIPTION
*
*       This function installs the vector table as required for the
*       given architecture
*
*   CALLED BY
*
*       ESAL_GE_ISR_Initialize
*
*   CALLS
*
*       ESAL_GE_MEM_Copy
*
*   INPUTS
*
*       None
*
*   OUTPUTS
*
*       None
*
***********************************************************************/
VOID    ESAL_AR_ISR_Vector_Table_Install(VOID)
{
    /* Set the VBR register to point to the vector table */
    ESAL_TS_RTE_VBR_WRITE((VOID *)&ESAL_AR_ISR_Vector_Table);
}

#if (ESAL_AR_ISR_RTI_MANDATORY == NU_TRUE)

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_AR_ISR_Return
*
*   DESCRIPTION
*
*       This function performs a "return from interrupt" or similar
*       architecture specific instruction to return the requested
*       function after servicing an interrupt.  
*
*   CALLED BY
*
*       OS Services
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       rtn_func_ptr                        Address of function to
*                                           return to
*
*   OUTPUTS
*
*       None
*
***********************************************************************/
VOID    ESAL_AR_ISR_Return(VOID (*rtn_func_ptr)(VOID))
{
#error  The SH1/2 architecture requires no return from interrupt.  Check settings in os/include/arch/sh/sh_defs.h
}

#endif  /* ESAL_AR_ISR_RTI_MANDATORY */

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_AR_INT_Enable
*
*   DESCRIPTION
*
*       This function enables the interrupt source on the architecture
*       that is associated with the specified vector ID
*
*   CALLED BY
*
*       ESAL_GE_INT_Enable
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       vector_id                           vector ID of interrupt
*                                           source being enabled
*       trigger_type                        Trigger method for given
*                                           interrupt vector ID
*       priority                            Priority for the given
*                                           interrupt vector ID
*
*   OUTPUTS
*
*       INT                                 vector_id if passed
*                                           ESAL_DP_INT_VECTOR_ID_DELIMITER
*                                           if failed
*
***********************************************************************/
INT     ESAL_AR_INT_Enable(INT                     vector_id,
                           ESAL_GE_INT_TRIG_TYPE   trigger_type,
                           INT                     priority)
{
    UINT16      temp16;


    /* Access unused parameters to avoid compiler warnings */
    NU_UNUSED_PARAM(priority);

    /* Check for rising edge trigger type */
    if (trigger_type == ESAL_TRIG_RISING_EDGE)
    {
        /* Get current ICR0 value */
        temp16 = ESAL_GE_MEM_READ16(ESAL_AR_INT_ICR0_BASE_ADDR);

        /* Set NMIE to rising edge and write new value */
        ESAL_GE_MEM_WRITE16(ESAL_AR_INT_ICR0_BASE_ADDR,
                            (temp16 | ESAL_PR_INT_ICR0_NMIE_BIT));
    }
    /* Check for falling edge trigger type */
    else if (trigger_type == ESAL_TRIG_FALLING_EDGE)
    {
        /* Get current ICR0 value */
        temp16 = ESAL_GE_MEM_READ16(ESAL_AR_INT_ICR0_BASE_ADDR);

        /* Clear NMIE to falling edge and write new value */
        ESAL_GE_MEM_WRITE16(ESAL_AR_INT_ICR0_BASE_ADDR,
                            (temp16 & ~ESAL_PR_INT_ICR0_NMIE_BIT));
    }

    /* Return the vector ID */
    return (vector_id);
}

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_AR_INT_Disable
*
*   DESCRIPTION
*
*       This function disables the interrupt source on the architecture
*       that is associated with the specified vector ID
*
*   CALLED BY
*
*       ESAL_GE_INT_Disable
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       vector_id                           Vector ID of interrupt
*                                           source being disabled
*
*   OUTPUTS
*
*       INT                                 vector_id if passed
*                                           ESAL_DP_INT_VECTOR_ID_DELIMITER
*                                           if failed
*
***********************************************************************/
INT     ESAL_AR_INT_Disable(INT vector_id)
{
    /* Return the vector ID */
    return (vector_id);
}

#if (ESAL_AR_OS_TIMER_USED == NU_TRUE)

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_AR_TMR_OS_Timer_Start
*
*   DESCRIPTION
*
*       This function starts the Operating System utilized timer.
*       This includes determining the required timer count for the
*       specified period, enabling the timer to produce this period,
*       and enabling the interrupt associated with this timer.
*
*   CALLED BY
*
*       ESAL_GE_TMR_OS_Timer_Start
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       ticks_per_sec                       Number of timer interrupts
*                                           that occur in a 1 sec period
*
*   OUTPUTS
*
*       None
*
***********************************************************************/
VOID    ESAL_AR_TMR_OS_Timer_Start(UINT32 ticks_per_sec)
{
#error  No Architecture level timer exists for SuperH MCU (SH1/SH2).  Check settings in os/include/arch/sh/sh_defs.h
}

#endif  /* ESAL_AR_OS_TIMER_USED */

#if (ESAL_CO_CACHE_AVAILABLE == NU_TRUE)

/***********************************************************************
*
*   FUNCTION
*
*       ESAL_CO_MEM_Cache_Enable
*
*   DESCRIPTION
*
*       This function initializes the cache as required
*       for the given core.  The memory region data structure
*       (ESAL_DP_MEM_Region_Data) should be utilized to perform
*       this initialization and the cache attributes in this
*       table should be correctly reflected.
*
*   CALLED BY
*
*       ESAL_GE_MEM_Initialize
*
*   CALLS
*
*       None
*
*   INPUTS
*
*       avail_mem                           Address of available memory
*
*   OUTPUTS
*
*       VOID *                              Updated available memory
*                                           address
*
***********************************************************************/
VOID    *ESAL_CO_MEM_Cache_Enable(VOID *avail_mem)
{
    /* Enable I and D cache. */
    ESAL_GE_MEM_WRITE32(ESAL_CO_MEM_CCR1_ADDR, 
                        (ESAL_CO_MEM_CCR1_ICF_BIT | ESAL_CO_MEM_CCR1_ICE_BIT |
                         ESAL_CO_MEM_CCR1_OCF_BIT | ESAL_CO_MEM_CCR1_OCE_BIT));

    /* Return updated available memory address to caller. */
    return (avail_mem);
}

#endif  /* ESAL_CO_CACHE_AVAILABLE */
