//------------------------------------------------------------------------------
// @file hal/micro/cortexm3/spmr.s79
// @brief SPMR (Special Purpose Mask Registers) manipulation routines.
// 
// Since the compiler does not provide low level intrinsic functions for some
// required operations, this file maintains the small set of assembly code
// needed to manipulate the Special Purpose Mask Registers.
// 
// While it is possible to add this functionality as inline assembly in C files,
// IAR highly recommends against this due to not only code being fragile in its
// surroundings, but it also negates the possibility of size optimization.
// 
// NOTE: This file looks more complicated than it really is.  It was originally
// generated by writing a C file and having the compiler generate the
// corresponding assembly file.  This is where all the CFI (Call Frame
// Information) expressions came from.  The CFI information enables proper debug
// backtrace ability.  The pieces to pay attention to are the actual funtions
// near the end.
//
// * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved.        -->
//------------------------------------------------------------------------------

#include "compiler/asm.h"

// NOTE!! IF THIS VALUE IS CHANGED, NVIC-CONFIG.H MUST ALSO BE UPDATED 
#define INTERRUPTS_DISABLED_PRIORITY (12 << 3)

        __EXPORT__ _readBasePri
        __EXPORT__ _writeBasePri
        __EXPORT__ _disableBasePri
        __EXPORT__ _basePriIsDisabled
        __EXPORT__ _enableBasePri
        __EXPORT__ _setPriMask
        __EXPORT__ _clearPriMask
        __EXPORT__ _executeBarrierInstructions

//------------------------------------------------------------------------------
//   int8u _readBasePri(void)
//
// Read and return the BASEPRI value.
//
//------------------------------------------------------------------------------
        __CODE__
        __THUMB__
        __CFI__(Block cfiBlock0 Using cfiCommon0)
        __CFI__(Function _readBasePri)
_readBasePri:
        MRS  R0, BASEPRI                    // read current BASEPRI
        BX   LR
        __CFI__(EndBlock cfiBlock0)

//------------------------------------------------------------------------------
//    void _writeBasePri(int8u priority)
//
// Write BASEPRI with the passed value to obtain the proper preemptive priority
// group masking. Note that the value passed must have been left shifted by 3
// to be properly aligned in the BASEPRI register.
// (Refer to nvic-config.h for the PRIGROUP table.)
//
//------------------------------------------------------------------------------
        __CODE__
        __THUMB__
        __CFI__(Block cfiBlock1 Using cfiCommon0)
        __CFI__(Function _writeBasePri)
_writeBasePri:
        MSR BASEPRI, R0                     // load BASEPRI from variable (R0)
        BX  LR
        __CFI__(EndBlock cfiBlock1)

//------------------------------------------------------------------------------
//   int8u _disableBasePri(void)
//
// Set BASEPRI to mask out interrupts but allow faults. It returns the value
// BASEPRI had when it was called.
//
//------------------------------------------------------------------------------
        __CODE__
        __THUMB__
        __CFI__(Block cfiBlock2 Using cfiCommon0)
        __CFI__(Function _disableBasePri)
_disableBasePri:
        MRS  R0, BASEPRI                        // read current BASEPRI
        LDR  R1, =INTERRUPTS_DISABLED_PRIORITY  // disable ints, allow faults
        MSR  BASEPRI, R1                     
        BX   LR
        __CFI__(EndBlock cfiBlock2)
  
//------------------------------------------------------------------------------
//   boolean _basePriIsDisabled(void)
//
// Compare BASEPRI to the priority used to disable interrupts (but not faults). 
// Return TRUE if the priority is higher or equal to that.
//
//------------------------------------------------------------------------------
        __CODE__
        __THUMB__
        __CFI__(Block cfiBlock3 Using cfiCommon0)
        __CFI__(Function _basePriIsDisabled)
_basePriIsDisabled:
        MRS  R0, BASEPRI                    // read current BASEPRI
        CMP  R0, #INTERRUPTS_DISABLED_PRIORITY
        ITE  lt
        LDRLT R0, =0
        LDRGE R0, =1
        BX   LR
        __CFI__(EndBlock cfiBlock3)

//------------------------------------------------------------------------------
//   void _enableBasePri(void)
// 
// Set BASEPRI to 0, which disables it from masking any interrupts.
//
//------------------------------------------------------------------------------
        __CODE__
        __THUMB__
        __CFI__(Block cfiBlock4 Using cfiCommon0)
        __CFI__(Function _enableBasePri)
_enableBasePri:
        LDR  R1, = 0                        // zero disables BASEPRI masking
        MSR  BASEPRI, R1                     
        BX   LR
        __CFI__(EndBlock cfiBlock4)

//------------------------------------------------------------------------------
//   void _setPriMask(void)
//
// Set the 1-bit PRIMASK register, which sets the base priority to 0. This
// locks out all interrupts and configurable faults (usage, memory management
// and bus faults).
//
// Note: generally speaking PRIMASK should not be set because faults should
// be enabled even when interrupts are disabled. If they are not enabled,
// a fault will immediately escalate to a hard fault.
//
//------------------------------------------------------------------------------
        __CODE__
        __THUMB__
        __CFI__(Block cfiBlock5 Using cfiCommon0)
        __CFI__(Function _setPriMask)
_setPriMask:
        CPSID i
        BX   LR
        __CFI__(EndBlock cfiBlock5)

//------------------------------------------------------------------------------
//   void _clearPriMask(void)
//
// Clears the 1-bit PRIMASK register, which allows the BASEPRI value to 
// mask interrupts (if non-zero).
//
//------------------------------------------------------------------------------
        __CODE__
        __THUMB__
        __CFI__(Block cfiBlock6 Using cfiCommon0)
        __CFI__(Function _clearPriMask)
_clearPriMask:
        CPSIE i
        BX   LR
        __CFI__(EndBlock cfiBlock6)

//------------------------------------------------------------------------------
//   void _executeBarrierInstructions(void)
//
//A utility function for inserting barrier instructions.  These
//instructions should be used whenever the MPU is enabled or disabled so
//that all memory/instruction accesses can complete before the MPU changes
//state. 
//
//------------------------------------------------------------------------------
        __CODE__
        __THUMB__
        __CFI__(Block cfiBlock7 Using cfiCommon0)
        __CFI__(Function _executeBarrierInstructions)
_executeBarrierInstructions:
        DMB
        DSB
        ISB
        BX   LR
        __CFI__(EndBlock cfiBlock7)

        __END__
