#ifndef __INTRINSICS_H__
#define __INTRINSICS_H__

#include "types.h"

// This function reverses the bit order of the given value.
__attribute__( ( always_inline ) ) static __INLINE uint32_t __RBIT(uint32_t value)
{
  uint32_t result;

   __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) );
   return(result);
}

// This function performs a exclusive LDR command for 8 bit value.
__attribute__( ( always_inline ) ) static __INLINE uint8_t __LDREXB(volatile uint8_t *addr)
{
    uint8_t result;

   __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) );
   return(result);
}

// This function performs a exclusive LDR command for 16 bit values.
__attribute__( ( always_inline ) ) static __INLINE uint16_t __LDREXH(volatile uint16_t *addr)
{
    uint16_t result;

   __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) );
   return(result);
}

//  This function performs a exclusive LDR command for 32 bit values.
__attribute__( ( always_inline ) ) static __INLINE uint32_t __LDREXW(volatile uint32_t *addr)
{
    uint32_t result;

   __ASM volatile ("ldrex %0, [%1]" : "=r" (result) : "r" (addr) );
   return(result);
}

// This function performs a exclusive STR command for 8 bit values.
__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr)
{
   uint32_t result;

   __ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
   return(result);
}

// This function performs a exclusive STR command for 16 bit values.
__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr)
{
   uint32_t result;

   __ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
   return(result);
}

// This function performs a exclusive STR command for 32 bit values.

__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr)
{
   uint32_t result;

   __ASM volatile ("strex %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
   return(result);
}

// This function removes the exclusive lock which is created by LDREX.
__attribute__( ( always_inline ) ) static __INLINE void __CLREX(void)
{
  __ASM volatile ("clrex");
}

// This macro saturates a signed value.

#define __SSAT(ARG1,ARG2) \
({                          \
  uint32_t __RES, __ARG1 = (ARG1); \
  __ASM ("ssat %0, %1, %2" : "=r" (__RES) :  "I" (ARG2), "r" (__ARG1) ); \
  __RES; \
 })

//    This function saturates an unsigned value.
#define __USAT(ARG1,ARG2) \
({                          \
  uint32_t __RES, __ARG1 = (ARG1); \
  __ASM ("usat %0, %1, %2" : "=r" (__RES) :  "I" (ARG2), "r" (__ARG1) ); \
  __RES; \
 })

// This function counts the number of leading zeros of a data value.
__attribute__( ( always_inline ) ) static __INLINE uint8_t __CLZ(uint32_t value)
{
  uint8_t result;

  __ASM volatile ("clz %0, %1" : "=r" (result) : "r" (value) );
  return(result);
}

//  This function enables IRQ interrupts by clearing the I-bit in the CPSR.
__attribute__( ( always_inline ) ) static __INLINE void __enable_irq(void)
{
  __ASM volatile ("cpsie i");
}

//  This function disables IRQ interrupts by setting the I-bit in the CPSR.
__attribute__( ( always_inline ) ) static __INLINE void __disable_irq(void)
{
  __ASM volatile ("cpsid i");
}

// This function returns the content of the Control Register.
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_CONTROL(void)
{
  uint32_t result;

  __ASM volatile ("MRS %0, control" : "=r" (result) );
  return(result);
}

// This function writes the given value to the Control Register.
__attribute__( ( always_inline ) ) static __INLINE void __set_CONTROL(uint32_t control)
{
  __ASM volatile ("MSR control, %0" : : "r" (control) );
}

// This function returns the content of the ISPR Register
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_IPSR(void)
{
  uint32_t result;

  __ASM volatile ("MRS %0, ipsr" : "=r" (result) );
  return(result);
}

// This function returns the content of the APSR Register.
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_APSR(void)
{
  uint32_t result;

  __ASM volatile ("MRS %0, apsr" : "=r" (result) );
  return(result);
}

//    This function returns the content of the xPSR Register.
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_xPSR(void)
{
  uint32_t result;

  __ASM volatile ("MRS %0, xpsr" : "=r" (result) );
  return(result);
}

// This function returns the current value of the Process Stack Pointer (PSP).
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_PSP(void)
{
  register uint32_t result;

  __ASM volatile ("MRS %0, psp\n"  : "=r" (result) );
  return(result);
}

// This function assigns the given value to the Process Stack Pointer (PSP).
__attribute__( ( always_inline ) ) static __INLINE void __set_PSP(uint32_t topOfProcStack)
{
  __ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) );
}

// This function returns the current value of the Main Stack Pointer (MSP).
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_MSP(void)
{
  register uint32_t result;

  __ASM volatile ("MRS %0, msp\n" : "=r" (result) );
  return(result);
}

// This function assigns the given value to the Main Stack Pointer (MSP).
__attribute__( ( always_inline ) ) static __INLINE void __set_MSP(uint32_t topOfMainStack)
{
  __ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) );
}

// This function returns the current state of the priority mask bit from the Priority Mask Register.
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_PRIMASK(void)
{
  uint32_t result;

  __ASM volatile ("MRS %0, primask" : "=r" (result) );
  return(result);
}

// This function assigns the given value to the Priority Mask Register.
__attribute__( ( always_inline ) ) static __INLINE void __set_PRIMASK(uint32_t priMask)
{
  __ASM volatile ("MSR primask, %0" : : "r" (priMask) );
}

// This function enables FIQ interrupts by clearing the F-bit in the CPSR.
__attribute__( ( always_inline ) ) static __INLINE void __enable_fault_irq(void)
{
  __ASM volatile ("cpsie f");
}

// This function disables FIQ interrupts by setting the F-bit in the CPSR.
__attribute__( ( always_inline ) ) static __INLINE void __disable_fault_irq(void)
{
  __ASM volatile ("cpsid f");
}

// This function returns the current value of the Base Priority register.
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_BASEPRI(void)
{
  uint32_t result;

  __ASM volatile ("MRS %0, basepri_max" : "=r" (result) );
  return(result);
}

// This function assigns the given value to the Base Priority register.
__attribute__( ( always_inline ) ) static __INLINE void __set_BASEPRI(uint32_t value)
{
  __ASM volatile ("MSR basepri, %0" : : "r" (value) );
}

//    This function returns the current value of the Fault Mask register.
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_FAULTMASK(void)
{
  uint32_t result;

  __ASM volatile ("MRS %0, faultmask" : "=r" (result) );
  return(result);
}

// This function assigns the given value to the Fault Mask register.
__attribute__( ( always_inline ) ) static __INLINE void __set_FAULTMASK(uint32_t faultMask)
{
  __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) );
}

#endif // __INTRINSICS_H__

