/***********************************************************************
*
*             Copyright 2012 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
*
*       xtensa_defs.h
*
*   DESCRIPTION
*
*       This file contains all definitions, structures, etc for the
*       base Xtensa architecture.
*
*   DATA STRUCTURES
*
*       None
*
*   DEPENDENCIES
*
*       None
*
***********************************************************************/

#ifndef         XTENSA_DEFS_H
#define         XTENSA_DEFS_H

#include <xtensa/config/core.h>

/* Define if the OS timer is part of the architecture (NU_TRUE)
   NOTE:  The OS timer can be located at only one of the following levels of
          abstraction: the processor level or the architecture level.
          If ESAL_AR_OS_TIMER_USED is NU_TRUE, the OS timer is contained
          within the architecture.  If ESAL_AR_OS_TIMER_USED is NU_FALSE,
          the OS timer is contained within the processor component. */
#define         ESAL_AR_OS_TIMER_USED                   NU_FALSE

/* Define if architecture supports unaligned 16-bit accesses to memory. */
#define         ESAL_AR_UNALIGNED_16BIT_SPT             NU_FALSE

/* Define if architecture supports unaligned 32-bit accesses to memory. */
#define         ESAL_AR_UNALIGNED_32BIT_SPT             NU_FALSE

/* Define number of accesses required to read or write a pointer */
#define         ESAL_AR_PTR_ACCESS                      1

/* Define number of accesses required to read or write a 32-bit value */
#define         ESAL_AR_32BIT_ACCESS                    1

/* Define reverse bit ordering in PPC.  This makes many of the ESAL
   memory macros use reverse-bit ordering (bit 0 is most-significant bit) */
#define         ESAL_AR_REVERSE_BIT_ORDERING

/* Size, in bytes, of architecture system stack.  This stack will be
   utilized when servicing interrupts. */
#define         ESAL_AR_SYSTEM_STACK_SIZE               CFG_NU_OS_ARCH_XTENSA_COM_SYSTEM_STACK_SIZE

/* Size, in bytes, of architecture exception stack.  This stack will be
   utilized when servicing exceptions. */
#define         ESAL_AR_EXCEPTION_STACK_SIZE            0

/* Define if interrupt servicing initialization is required at the
   architecture level. */
#define         ESAL_AR_ISR_INIT_REQUIRED               NU_TRUE

/* Define if architecture mandates that all interrupt handlers perform a
   "return from interrupt" (RTI) instruction in order for the hardware to
   correctly restore the state of execution to the pre-interrupt condition.
   NOTE:  Most architectures allow the state of execution to be restored
          without needing to perform an RTI.  In most cases, this will be set
          to NU_FALSE */
#define         ESAL_AR_ISR_RTI_MANDATORY               NU_FALSE

/* Define bit values for the architecture's status register / machine state register /
   etc that are used to enable and disable interrupts for the given architecture. */
#define         ESAL_AR_INTERRUPTS_DISABLE_BITS         XCHAL_EXCM_LEVEL
#define         ESAL_AR_INTERRUPTS_ENABLE_BITS          0x00000000

/* Define ESAL interrupt vector IDs for this architecture.
   These IDs match up with architecture interrupts.
   Values correspond to the index of entries in ESAL_GE_ISR_Interrupt_Handler[].
   Names are of the form ESAL_AR_<Name>_INT_VECTOR_ID, where <Name> comes
   directly from the hardware documentation */
#define         ESAL_AR_LEVEL1_INT_VECTOR_ID        0
#define         ESAL_AR_LEVEL2_INT_VECTOR_ID        1
#define         ESAL_AR_LEVEL3_INT_VECTOR_ID        2
#define         ESAL_AR_LEVEL4_INT_VECTOR_ID        3
#define         ESAL_AR_LEVEL5_INT_VECTOR_ID        4
#define         ESAL_AR_LEVEL6_INT_VECTOR_ID        5
#define         ESAL_AR_LEVEL7_INT_VECTOR_ID        6


/* Define the last ESAL exception vector ID for this architecture + 1 */
#define         ESAL_AR_INT_VECTOR_ID_DELIMITER          (ESAL_AR_LEVEL7_INT_VECTOR_ID + 1)

/* Define ESAL exception vector IDs for this architecture.
   These IDs match up with architecture exceptions.
   Values correspond to the index of entries in ESAL_GE_ISR_Exception_Handler[].
   Names are of the form ESAL_AR_<Name>_EXCEPT_VECTOR_ID, where <Name> comes
   directly from the hardware documentation */
#define         ESAL_AR_EXCEPT_VECTOR_ID_DELIMITER  0

/* Define variable(s) required to save / restore architecture interrupt state.
   These variable(s) are used in conjunction with the ESAL_AR_INT_ALL_DISABLE() and
   ESAL_AR_INT_ALL_RESTORE() macros to hold any data that must be preserved in
   order to allow these macros to function correctly. */
#define         ESAL_AR_INT_CONTROL_VARS            UINT32 esal_tmp_val;

/* Interrupt level mask. */
#define         ESAL_AR_INTERRUPTS_MASK_BITS        0x0000000F

/* This macro locks out interrupts and saves the current
   architecture status register / state register to the specified
   address.  This function does not attempt to mask any bits in
   the return register value and can be used as a quick method
   to guard a critical section.
   NOTE:  This macro is used in conjunction with ESAL_AR_INT_ALL_RESTORE
          defined below and ESAL_AR_INT_CONTROL_VARS defined above. */
#define         ESAL_AR_INT_ALL_DISABLE()                                       \
                {                                                               \
                    ESAL_TS_RTE_READ_PS(esal_tmp_val);                          \
                    esal_tmp_val &= ESAL_AR_INTERRUPTS_MASK_BITS;               \
                    ESAL_TS_RTE_SET_INT_LEVEL(ESAL_AR_INTERRUPTS_DISABLE_BITS); \
                }

/* This macro restores the architecture status / state register
   used to lockout interrupts to the value provided.  The
   intent of this function is to be a fast mechanism to restore the
   interrupt level at the end of a critical section to its
   original level.
   NOTE:  This macro is used in conjunction with ESAL_AR_INT_ALL_DISABLE
          and ESAL_AR_INT_CONTROL_VARS defined above. */
#define         ESAL_AR_INT_ALL_RESTORE()                                       \
                {                                                               \
                    ESAL_AR_INT_BITS_SET(esal_tmp_val);                         \
                }

/* This macro locks-out interrupts but doesn't save the status
   register / control register value. */
#define         ESAL_AR_INT_FAST_ALL_DISABLE()                                  \
                {                                                               \
                    ESAL_TS_RTE_SET_INT_LEVEL(ESAL_AR_INTERRUPTS_DISABLE_BITS); \
                }

/* This macro unlocks interrupts but doesn't save the status
   register / control register value. */
#define         ESAL_AR_INT_FAST_ALL_ENABLE()                                   \
                {                                                               \
                    ESAL_TS_RTE_SET_INT_LEVEL(ESAL_AR_INTERRUPTS_ENABLE_BITS);  \
                }

/* This macro sets the interrupt related bits in the status register / control
   register to the specified value. */
#define         ESAL_AR_INT_BITS_SET(set_bits)                                  \
                {                                                               \
                    INT     tmp_val;                                            \
                                                                                \
                    ESAL_TS_RTE_READ_PS(tmp_val);                               \
                    tmp_val &= ~ESAL_AR_INTERRUPTS_MASK_BITS;                   \
                    tmp_val |= set_bits;                                        \
                    ESAL_TS_RTE_WRITE_PS(tmp_val);                              \
                    ESAL_TS_RTE_SYNC();                                         \
                }

/* This macro gets the interrupt related bits from the status register / control
   register. */
#define         ESAL_AR_INT_BITS_GET(get_bits_ptr)                              \
                {                                                               \
                    INT     tmp_val;                                            \
                                                                                \
                    ESAL_TS_RTE_READ_PS(tmp_val);                               \
                    tmp_val &= ESAL_AR_INTERRUPTS_MASK_BITS;                    \
                    *get_bits_ptr = tmp_val;                                    \
                }

/* Determines where the ISR nesting counter is incremented.  
   When set to 0 the increment occurs in assembly files, when 
   set to 1 the increment will occur in c files. */
#define         ESAL_AR_ISR_INCREMENT_IN_C                  NU_TRUE

/* Define architecture interrupt handling constants,
   register addresses, initialization values, structures, etc. */
#if XCHAL_CP_NUM > 0

#define ESAL_AR_CP_ALIGN_CHECK(align)  (align < 4 ? 4 : align)

/*  Offsets of each element in the save area.  */
#define ESAL_AR_CP0_SA      4
#define ESAL_AR_CP1_SA      ESAL_GE_MEM_PTR_ALIGN(ESAL_AR_CP0_SA + XCHAL_CP0_SA_SIZE, ESAL_AR_CP_ALIGN_CHECK(XCHAL_CP1_SA_ALIGN))
#define ESAL_AR_CP2_SA      ESAL_GE_MEM_PTR_ALIGN(ESAL_AR_CP1_SA + XCHAL_CP1_SA_SIZE, ESAL_AR_CP_ALIGN_CHECK(XCHAL_CP2_SA_ALIGN))
#define ESAL_AR_CP3_SA      ESAL_GE_MEM_PTR_ALIGN(ESAL_AR_CP2_SA + XCHAL_CP2_SA_SIZE, ESAL_AR_CP_ALIGN_CHECK(XCHAL_CP3_SA_ALIGN))
#define ESAL_AR_CP4_SA      ESAL_GE_MEM_PTR_ALIGN(ESAL_AR_CP3_SA + XCHAL_CP3_SA_SIZE, ESAL_AR_CP_ALIGN_CHECK(XCHAL_CP4_SA_ALIGN))
#define ESAL_AR_CP5_SA      ESAL_GE_MEM_PTR_ALIGN(ESAL_AR_CP4_SA + XCHAL_CP4_SA_SIZE, ESAL_AR_CP_ALIGN_CHECK(XCHAL_CP5_SA_ALIGN))
#define ESAL_AR_CP6_SA      ESAL_GE_MEM_PTR_ALIGN(ESAL_AR_CP5_SA + XCHAL_CP5_SA_SIZE, ESAL_AR_CP_ALIGN_CHECK(XCHAL_CP6_SA_ALIGN))
#define ESAL_AR_CP7_SA      ESAL_GE_MEM_PTR_ALIGN(ESAL_AR_CP6_SA + XCHAL_CP6_SA_SIZE, ESAL_AR_CP_ALIGN_CHECK(XCHAL_CP7_SA_ALIGN))
#define ESAL_AR_CP_SA_SIZE  ESAL_GE_MEM_PTR_ALIGN(ESAL_AR_CP7_SA + XCHAL_CP7_SA_SIZE, 16)

/*  Overall size allows for dynamic alignment, includes CP 0-7 and enable  */
#define ESAL_AR_CP_SIZE     (ESAL_AR_CP_SA_SIZE + XCHAL_TOTAL_SA_ALIGN)

#define ESAL_AR_CP_GET_SAVE_AREA(thread)         ((thread -> tc_stack_end) - (sizeof(UINT32) * 2))
#define ESAL_AR_CP_GET_CP_OFFSET(coproc)         (ESAL_AR_ISR_Coproc_Offset[coproc])
#define ESAL_AR_CP_GET_CPENABLE(thread)          ((thread -> tc_stack_end) - sizeof(UINT32))

#else

#define ESAL_AR_CP_SIZE     0

#endif

/* Define xtensa architecture stack frame size 
 * NOTE : Size must be a 16-byte multiple to keep stacks 16-byte aligned */
#define         ESAL_AR_STK_FRAME_SIZE            (((0x74 + XCHAL_NCP_SA_SIZE) + 15) & (~0xF))

/* Define size of register spill save area in bytes */
#define         ESAL_AR_STK_SAVE_AREA_SIZE        16

/* Define bit mask to clear PS.INTLEVEL field */
#define         ESAL_AR_STK_PS_INTLEVEL_CLEAR      (~(PS_INTLEVEL_MASK))

/* Define xtensa architecture stack frame offsets */
#define         ESAL_AR_STK_OFFSET_TYPE           0x00     /* 0 (solicited) or dispatch return PC */
#define         ESAL_AR_STK_OFFSET_PC             0x04
#define         ESAL_AR_STK_OFFSET_PS             0x08
#define         ESAL_AR_STK_OFFSET_A0             0x0C
#define         ESAL_AR_STK_OFFSET_A1             0x10
#define         ESAL_AR_STK_OFFSET_A2             0x14
#define         ESAL_AR_STK_OFFSET_A3             0x18
#define         ESAL_AR_STK_OFFSET_A4             0x1C
#define         ESAL_AR_STK_OFFSET_A5             0x20
#define         ESAL_AR_STK_OFFSET_A6             0x24
#define         ESAL_AR_STK_OFFSET_A7             0x28
#define         ESAL_AR_STK_OFFSET_A8             0x2C
#define         ESAL_AR_STK_OFFSET_A9             0x30
#define         ESAL_AR_STK_OFFSET_A10            0x34
#define         ESAL_AR_STK_OFFSET_A11            0x38
#define         ESAL_AR_STK_OFFSET_A12            0x3C
#define         ESAL_AR_STK_OFFSET_A13            0x40
#define         ESAL_AR_STK_OFFSET_A14            0x44
#define         ESAL_AR_STK_OFFSET_A15            0x48
#define         ESAL_AR_STK_OFFSET_SAR            0x4C
#define         ESAL_AR_STK_OFFSET_LBEG           0x50    /* Loop option only */
#define         ESAL_AR_STK_OFFSET_LEND           0x54    /* Loop option only */
#define         ESAL_AR_STK_OFFSET_LCOUNT         0x58    /* Loop option only */
#define         ESAL_AR_STK_OFFSET_EXCCAUSE       0x5C    /* temp: EXCCAUSE register value */
#define         ESAL_AR_STK_OFFSET_THISLEVEL      0x60    /* temp: mask of interrupts at this level */
#define         ESAL_AR_STK_OFFSET_PS_C           0x64    /* temp: PS value to use for C code */
#define         ESAL_AR_STK_OFFSET_EXTRA          0x70    /* Extra register save base offset */

/* Define architecture ESAL interrupt vector IDs.
   These IDs match up with architecture interrupt Levels.
   Values correspond to the index of entries in ESAL_GE_ISR_Interrupt_Handler[]. */

#define         ESAL_AR_LEVEL1_INT_VECTOR_ID      0
#define         ESAL_AR_LEVEL2_INT_VECTOR_ID      1
#define         ESAL_AR_LEVEL3_INT_VECTOR_ID      2
#define         ESAL_AR_LEVEL4_INT_VECTOR_ID      3
#define         ESAL_AR_LEVEL5_INT_VECTOR_ID      4
#define         ESAL_AR_LEVEL6_INT_VECTOR_ID      5
#define         ESAL_AR_LEVEL7_INT_VECTOR_ID      6

/* Define to allow conditional assembling of lowlevel ISR hook.
   Setting this to TRUE will allow a low-level hook to be executed in the
   interrupt handlers */

#define         ESAL_AR_ISR_HOOK_ENABLED         0

/* Define stack frame structure for minimum architecture registers required
   to be saved in order to enter a C environment during in interrupt / exception.
   These registers are the "scratch" registers that will not be preserved across
   a function call boundary and any interrupt state registers that must preserved
   to allow interrupt nesting. */
typedef struct
{
    UINT32          rtn_address;
    UINT32          reg_ps;
    UINT32          a0;
    UINT32          a1;
    UINT32          a2;
    UINT32          a3;
    UINT32          a4;
    UINT32          a5;
    UINT32          a6;
    UINT32          a7;
    UINT32          a8;
    UINT32          a9;
    UINT32          a10;
    UINT32          a11;
    UINT32          a12;
    UINT32          a13;
    UINT32          a14;
    UINT32          a15;
    UINT32          reg_sar;
    UINT32          reg_lbegin;
    UINT32          reg_lend;
    UINT32          reg_lcount;
    UINT32          reg_exccause;
    UINT32          reg_this_level;
    UINT32          reg_ps_c;
                    /* To force 16-byte alignment of xthal_extra field */
    UINT32          alignment_padding_1[2];
    UINT8           xthal_extra[XCHAL_NCP_SA_SIZE];
#if ((XCHAL_NCP_SA_SIZE % 16) > 0)
                    /* To force 16-byte alignment of the stack frame */
    UINT8           alignment_padding_2[(16-(XCHAL_NCP_SA_SIZE % 16))];
#endif
} ESAL_AR_STK_MIN;

/* Define stack frame structure for the architecture supported.
   This stack frame contains all registers that must be preserved
   across an (unsolicited) interrupt context switch.
   NOTE:  This stack frame includes the minimum stack frame
          defined above AND all other registers for the given
          architecture. */
typedef struct  ESAL_AR_STK_STRUCT
{
    UINT32          stack_type;
    
    ESAL_AR_STK_MIN min_stack;

} ESAL_AR_STK;

/* Define core cache availability
   NOTE:  A differentiation is made in ESAL between cache that
          is contained on a processor and cache that is
          inherent as part of a core (L2 vs L1 cache). */
#define         ESAL_CO_CACHE_AVAILABLE          NU_TRUE

/* Define for cache manipulation functions on Xtensa Processoers */

#define         ESAL_CO_TLB_PPN_MASK             0xE0000000
#define         ESAL_CO_TLB_VPN_MASK             0xE0000000
#define         ESAL_CO_TLB_CACHE_WRTHRU         0x00000001
#define         ESAL_CO_TLB_CACHE_WRBACK         0x00000004
#define         ESAL_CO_TLB_BYPASS_CACHE         0x00000002

#if (ESAL_CO_CACHE_AVAILABLE == NU_TRUE)

/* This macro invalidates all of the cache at the core level. */
#define         ESAL_CO_MEM_CACHE_ALL_INVALIDATE()                          \
                {                                                           \
                }

/* This macro invalidates all of the instruction cache at the core level. */
#define         ESAL_CO_MEM_ICACHE_ALL_INVALIDATE()                         \
                {                                                           \
                }

/* This macro invalidates all of the data cache at the core level. */
#define         ESAL_CO_MEM_DCACHE_ALL_INVALIDATE()                         \
                {                                                           \
                }

/* This macro invalidates all instruction cache for the specified address
   range at the core level. */
#define         ESAL_CO_MEM_ICACHE_INVALIDATE(addr, size)                   \
                {                                                           \
                    NU_UNUSED_PARAM(addr);                                  \
                    NU_UNUSED_PARAM(size);                                  \
                                                                            \
                    /* No method to invalidate a range in E500 core */      \
                    /* invalidating all ICache */                           \
                    ESAL_CO_MEM_ICACHE_ALL_INVALIDATE();                    \
                }

/* This macro invalidates all data cache for the specified address
   range at the core level. */
#define         ESAL_CO_MEM_DCACHE_INVALIDATE(addr, size)                   \
                {                                                           \
                    NU_UNUSED_PARAM(addr);                                  \
                    NU_UNUSED_PARAM(size);                                  \
                                                                            \
                    /* No method to invalidate a range in E500 core */      \
                    /* invalidating all DCache */                           \
                    ESAL_CO_MEM_DCACHE_ALL_INVALIDATE();                    \
                }

/* This macro flushes all data cache to physical memory (writeback cache)
   and invalidates all data cache entries at the core level. */
#define         ESAL_CO_MEM_DCACHE_ALL_FLUSH_INVAL()                        \
                {                                                           \
                    /* No method to flush DCache in E500 core */            \
                    /* invalidating all DCache */                           \
                    ESAL_CO_MEM_DCACHE_ALL_INVALIDATE();                    \
                }

/* This macro flushes all data cache to physical memory (writeback cache)
   for the given address range, then invalidates all data cache entries
   at the core level. */
#define         ESAL_CO_MEM_DCACHE_FLUSH_INVAL(addr, size)                  \
                {                                                           \
                    NU_UNUSED_PARAM(addr);                                  \
                    NU_UNUSED_PARAM(size);                                  \
                                                                            \
                    /* No method to flush DCache in E500 core */            \
                    /* invalidating all DCache */                           \
                    ESAL_CO_MEM_DCACHE_ALL_INVALIDATE();                    \
                }

#endif  /* ESAL_CO_CACHE_AVAILABLE == NU_TRUE */

#endif  /* XTENSA_DEFS_H */

