/*
 * arm_isr.h
 *
 *  Created on: 13 мар. 2019 г.
 *      Author: Lityagin Aleksandr
 *              alexrayne <alexraynepe196@gmail.com>
  ------------------------------------------------------------------------
    Copyright (c) alexrayne

   All rights reserved.
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
   - Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
   - Neither the name of ARM nor the names of its contributors may be used
     to endorse or promote products derived from this software without
     specific prior written permission.
   *
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE. *
 *-------------------------------------------------------------------
 * общий код управления прерыванияи ARM процессоров.
 * WARN: этот код длоен вставляться из <mcu_isr.h>
 *  mcu_isr.h связывается с конкретным CMSIS
 */

#ifndef HAL_CMSIS_ISR_H_
#define HAL_CMSIS_ISR_H_

// если ОС расчитыает на то что некоторые пиоритетные прерывания ВСЕГДА работают,
//  и неотменимы она может установить это
#ifndef OSPRIO_MAX
#define OSPRIO_MAX  (1<<(8-__NVIC_PRIO_BITS))
#endif


/*-----------------------------------------------------------*/
typedef int32_t isr_save_t;

#if defined ( __GNUC__ )

__STATIC_FORCEINLINE
void gie_enable( void )
{
uint32_t ulNewBASEPRI;

    __asm volatile
    (
        "   mov %0, %1                                              \n" \
        "   msr basepri, %0                                         \n" \
        "   isb                                                     \n" \
        "   dsb                                                     \n" \
        :"=r" (ulNewBASEPRI) : "i" ( 0 ) : "memory"
    );
}

/*-----------------------------------------------------------*/

__STATIC_FORCEINLINE
uint32_t gie_disable( void )
{
uint32_t ulOriginalBASEPRI, ulNewBASEPRI;

    __asm volatile
    (
        "   mrs %0, basepri                                         \n" \
        "   mov %1, %2                                              \n" \
        "   msr basepri, %1                                         \n" \
        "   isb                                                     \n" \
        "   dsb                                                     \n" \
        :"=r" (ulOriginalBASEPRI), "=r" (ulNewBASEPRI) : "i" ( OSPRIO_MAX ) : "memory"
    );

    /* This return will not be reached but is necessary to prevent compiler
    warnings. */
    return ulOriginalBASEPRI;
}
/*-----------------------------------------------------------*/

__STATIC_FORCEINLINE
void gie_restore( uint32_t ulNewMaskValue )
{
    __asm volatile
    (
        "   msr basepri, %0 " :: "r" ( ulNewMaskValue ) : "memory"
    );
}
/*-----------------------------------------------------------*/
#elif defined ( __CC_ARM )

__STATIC_FORCEINLINE
void gie_enable( void )
{
    __asm
    {
        /* Set BASEPRI to 0 so no interrupts are masked.  This function is only
        used to lower the mask in an interrupt, so memory barriers are not
        used. */
        msr basepri, #0
    }
}

/*-----------------------------------------------------------*/

__STATIC_FORCEINLINE
uint32_t gie_disable( void )
{
    uint32_t ulOriginalBASEPRI;
    uint32_t ulNewBASEPRI = OSPRIO_MAX;

    __asm
    {
        /* Set BASEPRI to the max syscall priority to effect a critical
        section. */
        mrs ulOriginalBASEPRI, basepri
        msr basepri, ulNewBASEPRI
        dsb
        isb
    }

    /* This return will not be reached but is necessary to prevent compiler
    warnings. */
    return ulOriginalBASEPRI;
}
/*-----------------------------------------------------------*/

__STATIC_FORCEINLINE
void gie_restore( uint32_t ulNewMaskValue )
{
    __asm
    {
        /* Barrier instructions are not used as this function is only used to
        lower the BASEPRI value. */
        msr basepri, ulNewMaskValue
    }
}

#elif   defined ( __ICCARM__ )

#define gie_enable()    __set_BASEPRI( 0 )
//#define gie_restore(x)  __iar_builtin_set_interrupt_state(x)
#define gie_restore(x)  __set_BASEPRI( x )

__STATIC_FORCEINLINE
uint32_t gie_disable( void ){
    //uint32_t res = __iar_builtin_get_interrupt_state()
    uint32_t res = __get_BASEPRI();
    __set_BASEPRI( OSPRIO_MAX );
    __DSB();
    __ISB();
    return res;
}

#else
#error "unckown compiler"
#endif



//-----------------------------------------------------------------------------
//                     uOS embedded
//  для этой ОС сделаем псевдонимы функций выше
typedef isr_save_t arch_state_t;
#define arch_intr_off()         gie_disable()
#define arch_intr_on()          gie_enable()
#define arch_intr_restore(x)    gie_restore(x)


#endif /* HAL_CMSIS_ISR_H_ */
