summaryrefslogblamecommitdiffstats
path: root/cpukit/score/cpu/arm/include/rtems/score/armv7m.h
blob: 1803c8d8ca31c4a535868bc028d4e39940c914ba (plain) (tree)
1
2
3
4
5
6
7
8





                                     
  
                                                                 








                                                          
                                        




                            
                            


                               




                        

                            




                                                




                      
               











                                               



















                          


                         

















                                           
                                               




                








                                             
                                                                     
                                            
                                                            


                                 














                                                                               
                 
 


                    



                                               
                 
 





                 







                                  













                                               
                                                               


















                            






























































































































































                                                                         

















                                                                               



















                                                 
                                  
                                  
                                                 


                                                    
                                                 
                                                   
 

                                           

                                               





                                                   

                                           

                                               











                                      


                                          

                                            

                                                         

                                                                       
 















































































                                                                   

































































                                                                     




















                                                             










                                                                    
   
                                                    
   





                                                

                                       







                                             

                                   























                                                                  
                                              


                                                              
                                          






































                                                        






                           












                                                                  

                

                                  




                                 
/**
 * @file
 *
 * @brief ARMV7M Architecture Support
 */

/*
 * Copyright (c) 2011-2014 Sebastian Huber.  All rights reserved.
 *
 *  embedded brains GmbH
 *  Obere Lagerstr. 30
 *  82178 Puchheim
 *  Germany
 *  <rtems@embedded-brains.de>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rtems.org/license/LICENSE.
 */

#ifndef RTEMS_SCORE_ARMV7M_H
#define RTEMS_SCORE_ARMV7M_H

#include <rtems/score/cpu.h>
#ifndef ASM
#include <rtems/score/assert.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#ifdef ARM_MULTILIB_ARCH_V7M

/* Coprocessor Access Control Register, CPACR */
#define ARMV7M_CPACR 0xe000ed88

#ifndef ASM

typedef struct {
  uint32_t reserved_0;
  uint32_t ictr;
  uint32_t actlr;
  uint32_t reserved_1;
} ARMV7M_ICTAC;

typedef void (*ARMV7M_Exception_handler)(void);

typedef struct {
  uint32_t register_r0;
  uint32_t register_r1;
  uint32_t register_r2;
  uint32_t register_r3;
  uint32_t register_r12;
  void *register_lr;
  void *register_pc;
  uint32_t register_xpsr;
#ifdef ARM_MULTILIB_VFP
  uint32_t register_s0;
  uint32_t register_s1;
  uint32_t register_s2;
  uint32_t register_s3;
  uint32_t register_s4;
  uint32_t register_s5;
  uint32_t register_s6;
  uint32_t register_s7;
  uint32_t register_s8;
  uint32_t register_s9;
  uint32_t register_s10;
  uint32_t register_s11;
  uint32_t register_s12;
  uint32_t register_s13;
  uint32_t register_s14;
  uint32_t register_s15;
  uint32_t register_fpscr;
  uint32_t reserved;
#endif
} ARMV7M_Exception_frame;

typedef struct {
  uint32_t comp;
  uint32_t mask;
  uint32_t function;
  uint32_t reserved;
} ARMV7M_DWT_comparator;

typedef struct {
#define ARMV7M_DWT_CTRL_NOCYCCNT (1U << 25)
#define ARMV7M_DWT_CTRL_CYCCNTENA (1U << 0)
  uint32_t ctrl;
  uint32_t cyccnt;
  uint32_t cpicnt;
  uint32_t exccnt;
  uint32_t sleepcnt;
  uint32_t lsucnt;
  uint32_t foldcnt;
  uint32_t pcsr;
  ARMV7M_DWT_comparator comparator[249];
#define ARMV7M_DWT_LAR_UNLOCK_MAGIC 0xc5acce55U
  uint32_t lar;
  uint32_t lsr;
} ARMV7M_DWT;

typedef struct {
  uint32_t cpuid;

#define ARMV7M_SCB_ICSR_NMIPENDSET (1U << 31)
#define ARMV7M_SCB_ICSR_PENDSVSET (1U << 28)
#define ARMV7M_SCB_ICSR_PENDSVCLR (1U << 27)
#define ARMV7M_SCB_ICSR_PENDSTSET (1U << 26)
#define ARMV7M_SCB_ICSR_PENDSTCLR (1U << 25)
#define ARMV7M_SCB_ICSR_ISRPREEMPT (1U << 23)
#define ARMV7M_SCB_ICSR_ISRPENDING (1U << 22)
#define ARMV7M_SCB_ICSR_VECTPENDING_GET(reg) (((reg) >> 12) & 0x1ffU)
#define ARMV7M_SCB_ICSR_RETTOBASE (1U << 11)
#define ARMV7M_SCB_ICSR_VECTACTIVE_GET(reg) ((reg) & 0x1ffU)
  uint32_t icsr;

  ARMV7M_Exception_handler *vtor;

#define ARMV7M_SCB_AIRCR_VECTKEY (0x05fa << 16)
#define ARMV7M_SCB_AIRCR_ENDIANESS (1U << 15)
#define ARMV7M_SCB_AIRCR_PRIGROUP_SHIFT 8
#define ARMV7M_SCB_AIRCR_PRIGROUP_MASK \
  ((0x7U) << ARMV7M_SCB_AIRCR_PRIGROUP_SHIFT)
#define ARMV7M_SCB_AIRCR_PRIGROUP(val) \
  (((val) << ARMV7M_SCB_AIRCR_PRIGROUP_SHIFT) & ARMV7M_SCB_AIRCR_PRIGROUP_MASK)
#define ARMV7M_SCB_AIRCR_PRIGROUP_GET(reg) \
  (((val) & ARMV7M_SCB_AIRCR_PRIGROUP_MASK) >> ARMV7M_SCB_AIRCR_PRIGROUP_SHIFT)
#define ARMV7M_SCB_AIRCR_PRIGROUP_SET(reg, val) \
  (((reg) & ~ARMV7M_SCB_AIRCR_PRIGROUP_MASK) | ARMV7M_SCB_AIRCR_PRIGROUP(val))
#define ARMV7M_SCB_AIRCR_SYSRESETREQ (1U << 2)
#define ARMV7M_SCB_AIRCR_VECTCLRACTIVE (1U << 1)
#define ARMV7M_SCB_AIRCR_VECTRESET (1U << 0)
  uint32_t aircr;

  uint32_t scr;
  uint32_t ccr;
  uint8_t shpr [12];

#define ARMV7M_SCB_SHCSR_USGFAULTENA (1U << 18)
#define ARMV7M_SCB_SHCSR_BUSFAULTENA (1U << 17)
#define ARMV7M_SCB_SHCSR_MEMFAULTENA (1U << 16)
  uint32_t shcsr;

  uint32_t cfsr;
  uint32_t hfsr;
  uint32_t dfsr;
  uint32_t mmfar;
  uint32_t bfar;
  uint32_t afsr;
  uint32_t reserved_e000ed40[18];
  uint32_t cpacr;
  uint32_t reserved_e000ed8c[106];
  uint32_t fpccr;
  uint32_t fpcar;
  uint32_t fpdscr;
  uint32_t mvfr0;
  uint32_t mvfr1;
} ARMV7M_SCB;

typedef struct {
#define ARMV7M_SYSTICK_CSR_COUNTFLAG (1U << 16)
#define ARMV7M_SYSTICK_CSR_CLKSOURCE (1U << 2)
#define ARMV7M_SYSTICK_CSR_TICKINT (1U << 1)
#define ARMV7M_SYSTICK_CSR_ENABLE (1U << 0)
  uint32_t csr;

  uint32_t rvr;
  uint32_t cvr;

#define ARMV7M_SYSTICK_CALIB_NOREF (1U << 31)
#define ARMV7M_SYSTICK_CALIB_SKEW (1U << 30)
#define ARMV7M_SYSTICK_CALIB_TENMS_GET(reg) ((reg) & 0xffffffU)
  uint32_t calib;
} ARMV7M_Systick;

typedef struct {
  uint32_t iser [8];
  uint32_t reserved_0 [24];
  uint32_t icer [8];
  uint32_t reserved_1 [24];
  uint32_t ispr [8];
  uint32_t reserved_2 [24];
  uint32_t icpr [8];
  uint32_t reserved_3 [24];
  uint32_t iabr [8];
  uint32_t reserved_4 [56];
  uint8_t  ipr [240];
  uint32_t reserved_5 [644];
  uint32_t stir;
} ARMV7M_NVIC;

typedef struct {
#define ARMV7M_MPU_TYPE_IREGION_GET(reg) (((reg) >> 16) & 0xffU)
#define ARMV7M_MPU_TYPE_DREGION_GET(reg) (((reg) >> 8) & 0xffU)
#define ARMV7M_MPU_TYPE_SEPARATE (1U << 0)
  uint32_t type;

#define ARMV7M_MPU_CTRL_PRIVDEFENA (1U << 2)
#define ARMV7M_MPU_CTRL_HFNMIENA (1U << 1)
#define ARMV7M_MPU_CTRL_ENABLE (1U << 0)
  uint32_t ctrl;

  uint32_t rnr;

#define ARMV7M_MPU_RBAR_ADDR_SHIFT 5
#define ARMV7M_MPU_RBAR_ADDR_MASK \
  ((0x7ffffffU) << ARMV7M_MPU_RBAR_ADDR_SHIFT)
#define ARMV7M_MPU_RBAR_ADDR(val) \
  (((val) << ARMV7M_MPU_RBAR_ADDR_SHIFT) & ARMV7M_MPU_RBAR_ADDR_MASK)
#define ARMV7M_MPU_RBAR_ADDR_GET(reg) \
  (((val) & ARMV7M_MPU_RBAR_ADDR_MASK) >> ARMV7M_MPU_RBAR_ADDR_SHIFT)
#define ARMV7M_MPU_RBAR_ADDR_SET(reg, val) \
  (((reg) & ~ARMV7M_MPU_RBAR_ADDR_MASK) | ARMV7M_MPU_RBAR_ADDR(val))
#define ARMV7M_MPU_RBAR_VALID (1U << 4)
#define ARMV7M_MPU_RBAR_REGION_SHIFT 0
#define ARMV7M_MPU_RBAR_REGION_MASK \
  ((0xfU) << ARMV7M_MPU_RBAR_REGION_SHIFT)
#define ARMV7M_MPU_RBAR_REGION(val) \
  (((val) << ARMV7M_MPU_RBAR_REGION_SHIFT) & ARMV7M_MPU_RBAR_REGION_MASK)
#define ARMV7M_MPU_RBAR_REGION_GET(reg) \
  (((val) & ARMV7M_MPU_RBAR_REGION_MASK) >> ARMV7M_MPU_RBAR_REGION_SHIFT)
#define ARMV7M_MPU_RBAR_REGION_SET(reg, val) \
  (((reg) & ~ARMV7M_MPU_RBAR_REGION_MASK) | ARMV7M_MPU_RBAR_REGION(val))
  uint32_t rbar;

#define ARMV7M_MPU_RASR_XN (1U << 28)
#define ARMV7M_MPU_RASR_AP_SHIFT 24
#define ARMV7M_MPU_RASR_AP_MASK \
  ((0x7U) << ARMV7M_MPU_RASR_AP_SHIFT)
#define ARMV7M_MPU_RASR_AP(val) \
  (((val) << ARMV7M_MPU_RASR_AP_SHIFT) & ARMV7M_MPU_RASR_AP_MASK)
#define ARMV7M_MPU_RASR_AP_GET(reg) \
  (((val) & ARMV7M_MPU_RASR_AP_MASK) >> ARMV7M_MPU_RASR_AP_SHIFT)
#define ARMV7M_MPU_RASR_AP_SET(reg, val) \
  (((reg) & ~ARMV7M_MPU_RASR_AP_MASK) | ARMV7M_MPU_RASR_AP(val))
#define ARMV7M_MPU_RASR_TEX_SHIFT 19
#define ARMV7M_MPU_RASR_TEX_MASK \
  ((0x7U) << ARMV7M_MPU_RASR_TEX_SHIFT)
#define ARMV7M_MPU_RASR_TEX(val) \
  (((val) << ARMV7M_MPU_RASR_TEX_SHIFT) & ARMV7M_MPU_RASR_TEX_MASK)
#define ARMV7M_MPU_RASR_TEX_GET(reg) \
  (((val) & ARMV7M_MPU_RASR_TEX_MASK) >> ARMV7M_MPU_RASR_TEX_SHIFT)
#define ARMV7M_MPU_RASR_TEX_SET(reg, val) \
  (((reg) & ~ARMV7M_MPU_RASR_TEX_MASK) | ARMV7M_MPU_RASR_TEX(val))
#define ARMV7M_MPU_RASR_S (1U << 18)
#define ARMV7M_MPU_RASR_C (1U << 17)
#define ARMV7M_MPU_RASR_B (1U << 16)
#define ARMV7M_MPU_RASR_SRD_SHIFT 8
#define ARMV7M_MPU_RASR_SRD_MASK \
  ((0xffU) << ARMV7M_MPU_RASR_SRD_SHIFT)
#define ARMV7M_MPU_RASR_SRD(val) \
  (((val) << ARMV7M_MPU_RASR_SRD_SHIFT) & ARMV7M_MPU_RASR_SRD_MASK)
#define ARMV7M_MPU_RASR_SRD_GET(reg) \
  (((val) & ARMV7M_MPU_RASR_SRD_MASK) >> ARMV7M_MPU_RASR_SRD_SHIFT)
#define ARMV7M_MPU_RASR_SRD_SET(reg, val) \
  (((reg) & ~ARMV7M_MPU_RASR_SRD_MASK) | ARMV7M_MPU_RASR_SRD(val))
#define ARMV7M_MPU_RASR_SIZE_SHIFT 1
#define ARMV7M_MPU_RASR_SIZE_MASK \
  ((0x1fU) << ARMV7M_MPU_RASR_SIZE_SHIFT)
#define ARMV7M_MPU_RASR_SIZE(val) \
  (((val) << ARMV7M_MPU_RASR_SIZE_SHIFT) & ARMV7M_MPU_RASR_SIZE_MASK)
#define ARMV7M_MPU_RASR_SIZE_GET(reg) \
  (((val) & ARMV7M_MPU_RASR_SIZE_MASK) >> ARMV7M_MPU_RASR_SIZE_SHIFT)
#define ARMV7M_MPU_RASR_SIZE_SET(reg, val) \
  (((reg) & ~ARMV7M_MPU_RASR_SIZE_MASK) | ARMV7M_MPU_RASR_SIZE(val))
#define ARMV7M_MPU_RASR_ENABLE (1U << 0)
  uint32_t rasr;

  uint32_t rbar_a1;
  uint32_t rasr_a1;
  uint32_t rbar_a2;
  uint32_t rasr_a2;
  uint32_t rbar_a3;
  uint32_t rasr_a3;
} ARMV7M_MPU;

typedef enum {
  ARMV7M_MPU_AP_PRIV_NO_USER_NO,
  ARMV7M_MPU_AP_PRIV_RW_USER_NO,
  ARMV7M_MPU_AP_PRIV_RW_USER_RO,
  ARMV7M_MPU_AP_PRIV_RW_USER_RW,
  ARMV7M_MPU_AP_PRIV_RO_USER_NO = 0x5,
  ARMV7M_MPU_AP_PRIV_RO_USER_RO,
} ARMV7M_MPU_Access_permissions;

typedef enum {
  ARMV7M_MPU_ATTR_R = ARMV7M_MPU_RASR_AP(ARMV7M_MPU_AP_PRIV_RO_USER_NO)
    | ARMV7M_MPU_RASR_C | ARMV7M_MPU_RASR_XN,
  ARMV7M_MPU_ATTR_RW = ARMV7M_MPU_RASR_AP(ARMV7M_MPU_AP_PRIV_RW_USER_NO)
    | ARMV7M_MPU_RASR_C | ARMV7M_MPU_RASR_XN | ARMV7M_MPU_RASR_B,
  ARMV7M_MPU_ATTR_RWX = ARMV7M_MPU_RASR_AP(ARMV7M_MPU_AP_PRIV_RW_USER_NO)
    | ARMV7M_MPU_RASR_C | ARMV7M_MPU_RASR_B,
  ARMV7M_MPU_ATTR_X = ARMV7M_MPU_RASR_AP(ARMV7M_MPU_AP_PRIV_NO_USER_NO)
    | ARMV7M_MPU_RASR_C,
  ARMV7M_MPU_ATTR_RX = ARMV7M_MPU_RASR_AP(ARMV7M_MPU_AP_PRIV_RO_USER_NO)
    | ARMV7M_MPU_RASR_C,
  ARMV7M_MPU_ATTR_IO = ARMV7M_MPU_RASR_AP(ARMV7M_MPU_AP_PRIV_RW_USER_NO)
    | ARMV7M_MPU_RASR_XN,
} ARMV7M_MPU_Attributes;

typedef enum {
  ARMV7M_MPU_SIZE_32_B = 0x4,
  ARMV7M_MPU_SIZE_64_B,
  ARMV7M_MPU_SIZE_128_B,
  ARMV7M_MPU_SIZE_256_B,
  ARMV7M_MPU_SIZE_512_B,
  ARMV7M_MPU_SIZE_1_KB,
  ARMV7M_MPU_SIZE_2_KB,
  ARMV7M_MPU_SIZE_4_KB,
  ARMV7M_MPU_SIZE_8_KB,
  ARMV7M_MPU_SIZE_16_KB,
  ARMV7M_MPU_SIZE_32_KB,
  ARMV7M_MPU_SIZE_64_KB,
  ARMV7M_MPU_SIZE_128_KB,
  ARMV7M_MPU_SIZE_256_KB,
  ARMV7M_MPU_SIZE_512_KB,
  ARMV7M_MPU_SIZE_1_MB,
  ARMV7M_MPU_SIZE_2_MB,
  ARMV7M_MPU_SIZE_4_MB,
  ARMV7M_MPU_SIZE_8_MB,
  ARMV7M_MPU_SIZE_16_MB,
  ARMV7M_MPU_SIZE_32_MB,
  ARMV7M_MPU_SIZE_64_MB,
  ARMV7M_MPU_SIZE_128_MB,
  ARMV7M_MPU_SIZE_256_MB,
  ARMV7M_MPU_SIZE_512_MB,
  ARMV7M_MPU_SIZE_1_GB,
  ARMV7M_MPU_SIZE_2_GB,
  ARMV7M_MPU_SIZE_4_GB
} ARMV7M_MPU_Size;

typedef struct {
  uint32_t rbar;
  uint32_t rasr;
} ARMV7M_MPU_Region;

#define ARMV7M_MPU_REGION_INITIALIZER(idx, addr, size, attr) \
  { \
    ((addr) & ARMV7M_MPU_RBAR_ADDR_MASK) \
      | ARMV7M_MPU_RBAR_VALID \
      | ARMV7M_MPU_RBAR_REGION(idx), \
    ARMV7M_MPU_RASR_SIZE(size) | (attr) | ARMV7M_MPU_RASR_ENABLE \
  }

#define ARMV7M_MPU_REGION_DISABLED_INITIALIZER(idx) \
  { \
    ARMV7M_MPU_RBAR_VALID | ARMV7M_MPU_RBAR_REGION(idx), \
    0 \
  }

/**
 * Higher level region configuration.
 *
 * Allows to configure with begin and end which is more convenient for
 * calculating the sizes from linker command file. Note that you still have to
 * follow the following rules:
 *
 * - Begin address has to be aligned to 0x20 (lower 5 bits set to 0)
 * - Sizes can only be a value of 2^x with a minimum of 32 Byte. If you have an
 *   end address that is not aligned, the region will get bigger.
 * - Later regions have higher priority.
 */
typedef struct {
  const void *begin;
  const void *end;
  uint32_t rasr;
} ARMV7M_MPU_Region_config;

typedef struct {
  uint32_t dhcsr;
  uint32_t dcrsr;
  uint32_t dcrdr;
#define ARMV7M_DEBUG_DEMCR_VC_CORERESET (1U << 0)
#define ARMV7M_DEBUG_DEMCR_VC_MMERR (1U << 4)
#define ARMV7M_DEBUG_DEMCR_VC_NOCPERR (1U << 5)
#define ARMV7M_DEBUG_DEMCR_VC_CHKERR (1U << 6)
#define ARMV7M_DEBUG_DEMCR_VC_STATERR (1U << 7)
#define ARMV7M_DEBUG_DEMCR_VC_BUSERR (1U << 8)
#define ARMV7M_DEBUG_DEMCR_VC_INTERR (1U << 9)
#define ARMV7M_DEBUG_DEMCR_VC_HARDERR (1U << 10)
#define ARMV7M_DEBUG_DEMCR_MON_EN (1U << 16)
#define ARMV7M_DEBUG_DEMCR_MON_PEND (1U << 17)
#define ARMV7M_DEBUG_DEMCR_MON_STEP (1U << 18)
#define ARMV7M_DEBUG_DEMCR_MON_REQ (1U << 19)
#define ARMV7M_DEBUG_DEMCR_TRCENA (1U << 24)
  uint32_t demcr;
} ARMV7M_DEBUG;

#define ARMV7M_DWT_BASE 0xe0001000
#define ARMV7M_SCS_BASE 0xe000e000
#define ARMV7M_ICTAC_BASE (ARMV7M_SCS_BASE + 0x0)
#define ARMV7M_SYSTICK_BASE (ARMV7M_SCS_BASE + 0x10)
#define ARMV7M_NVIC_BASE (ARMV7M_SCS_BASE + 0x100)
#define ARMV7M_SCB_BASE (ARMV7M_SCS_BASE + 0xd00)
#define ARMV7M_MPU_BASE (ARMV7M_SCS_BASE + 0xd90)
#define ARMV7M_DEBUG_BASE (ARMV7M_SCS_BASE + 0xdf0)

#define _ARMV7M_DWT \
  ((volatile ARMV7M_DWT *) ARMV7M_DWT_BASE)
#define _ARMV7M_ICTAC \
  ((volatile ARMV7M_ICTAC *) ARMV7M_ICTAC_BASE)
#define _ARMV7M_SCB \
  ((volatile ARMV7M_SCB *) ARMV7M_SCB_BASE)
#define _ARMV7M_Systick \
  ((volatile ARMV7M_Systick *) ARMV7M_SYSTICK_BASE)
#define _ARMV7M_NVIC \
  ((volatile ARMV7M_NVIC *) ARMV7M_NVIC_BASE)
#define _ARMV7M_MPU \
  ((volatile ARMV7M_MPU *) ARMV7M_MPU_BASE)
#define _ARMV7M_DEBUG \
  ((volatile ARMV7M_DEBUG *) ARMV7M_DEBUG_BASE)

#define ARMV7M_VECTOR_MSP 0
#define ARMV7M_VECTOR_RESET 1
#define ARMV7M_VECTOR_NMI 2
#define ARMV7M_VECTOR_HARD_FAULT 3
#define ARMV7M_VECTOR_MEM_MANAGE 4
#define ARMV7M_VECTOR_BUS_FAULT 5
#define ARMV7M_VECTOR_USAGE_FAULT 6
#define ARMV7M_VECTOR_SVC 11
#define ARMV7M_VECTOR_DEBUG_MONITOR 12
#define ARMV7M_VECTOR_PENDSV 14
#define ARMV7M_VECTOR_SYSTICK 15
#define ARMV7M_VECTOR_IRQ(n) ((n) + 16)
#define ARMV7M_IRQ_OF_VECTOR(n) ((n) - 16)

#define ARMV7M_EXCEPTION_PRIORITY_LOWEST 255

static inline bool _ARMV7M_Is_vector_an_irq( int vector )
{
  /* External (i.e. non-system) IRQs start after the SysTick vector. */
  return vector > ARMV7M_VECTOR_SYSTICK;
}

static inline uint32_t _ARMV7M_Get_basepri(void)
{
  uint32_t val;
  __asm__ volatile ("mrs %[val], basepri\n" : [val] "=&r" (val));
  return val;
}

static inline void _ARMV7M_Set_basepri(uint32_t val)
{
  __asm__ volatile ("msr basepri, %[val]\n" : : [val] "r" (val));
}

static inline uint32_t _ARMV7M_Get_primask(void)
{
  uint32_t val;
  __asm__ volatile ("mrs %[val], primask\n" : [val] "=&r" (val));
  return val;
}

static inline void _ARMV7M_Set_primask(uint32_t val)
{
  __asm__ volatile ("msr primask, %[val]\n" : : [val] "r" (val));
}

static inline uint32_t _ARMV7M_Get_faultmask(void)
{
  uint32_t val;
  __asm__ volatile ("mrs %[val], faultmask\n" : [val] "=&r" (val));
  return val;
}

static inline void _ARMV7M_Set_faultmask(uint32_t val)
{
  __asm__ volatile ("msr faultmask, %[val]\n" : : [val] "r" (val));
}

static inline uint32_t _ARMV7M_Get_control(void)
{
  uint32_t val;
  __asm__ volatile ("mrs %[val], control\n" : [val] "=&r" (val));
  return val;
}

static inline void _ARMV7M_Set_control(uint32_t val)
{
  __asm__ volatile ("msr control, %[val]\n" : : [val] "r" (val));
}

static inline uint32_t _ARMV7M_Get_MSP(void)
{
  uint32_t val;
  __asm__ volatile ("mrs %[val], msp\n" : [val] "=&r" (val));
  return val;
}

static inline void _ARMV7M_Set_MSP(uint32_t val)
{
  __asm__ volatile ("msr msp, %[val]\n" : : [val] "r" (val));
}

static inline uint32_t _ARMV7M_Get_PSP(void)
{
  uint32_t val;
  __asm__ volatile ("mrs %[val], psp\n" : [val] "=&r" (val));
  return val;
}

static inline void _ARMV7M_Set_PSP(uint32_t val)
{
  __asm__ volatile ("msr psp, %[val]\n" : : [val] "r" (val));
}

static inline uint32_t _ARMV7M_Get_XPSR(void)
{
  uint32_t val;
  __asm__ volatile ("mrs %[val], xpsr\n" : [val] "=&r" (val));
  return val;
}

static inline bool _ARMV7M_NVIC_Is_enabled( int irq )
{
  int index = irq >> 5;
  uint32_t bit = 1U << (irq & 0x1f);

  return (_ARMV7M_NVIC->iser [index] & bit) != 0;
}

static inline void _ARMV7M_NVIC_Set_enable( int irq )
{
  int index = irq >> 5;
  uint32_t bit = 1U << (irq & 0x1f);

  _ARMV7M_NVIC->iser [index] = bit;
}

static inline void _ARMV7M_NVIC_Clear_enable( int irq )
{
  int index = irq >> 5;
  uint32_t bit = 1U << (irq & 0x1f);

  _ARMV7M_NVIC->icer [index] = bit;
}

static inline bool _ARMV7M_NVIC_Is_pending( int irq )
{
  int index = irq >> 5;
  uint32_t bit = 1U << (irq & 0x1f);

  return (_ARMV7M_NVIC->ispr [index] & bit) != 0;
}

static inline void _ARMV7M_NVIC_Set_pending( int irq )
{
  int index = irq >> 5;
  uint32_t bit = 1U << (irq & 0x1f);

  _ARMV7M_NVIC->ispr [index] = bit;
}

static inline void _ARMV7M_NVIC_Clear_pending( int irq )
{
  int index = irq >> 5;
  uint32_t bit = 1U << (irq & 0x1f);

  _ARMV7M_NVIC->icpr [index] = bit;
}

static inline bool _ARMV7M_NVIC_Is_active( int irq )
{
  int index = irq >> 5;
  uint32_t bit = 1U << (irq & 0x1f);

  return (_ARMV7M_NVIC->iabr [index] & bit) != 0;
}

static inline void _ARMV7M_NVIC_Set_priority( int irq, int priority )
{
  _ARMV7M_NVIC->ipr [irq] = (uint8_t) priority;
}

static inline int _ARMV7M_NVIC_Get_priority( int irq )
{
  return _ARMV7M_NVIC->ipr [irq];
}

static inline bool _ARMV7M_DWT_Enable_CYCCNT( void )
{
  uint32_t demcr;
  uint32_t dwt_ctrl;

  demcr = _ARMV7M_DEBUG->demcr;
  _ARMV7M_DEBUG->demcr = demcr | ARMV7M_DEBUG_DEMCR_TRCENA;
  _ARM_Data_synchronization_barrier();

  dwt_ctrl = _ARMV7M_DWT->ctrl;
  if ((dwt_ctrl & ARMV7M_DWT_CTRL_NOCYCCNT) == 0) {
    _ARMV7M_DWT->lar = ARMV7M_DWT_LAR_UNLOCK_MAGIC;
    _ARM_Data_synchronization_barrier();
    _ARMV7M_DWT->ctrl = dwt_ctrl | ARMV7M_DWT_CTRL_CYCCNTENA;
    return true;
  } else {
    _ARMV7M_DEBUG->demcr = demcr;
    return false;
  }
}

int _ARMV7M_Get_exception_priority( int vector );

void _ARMV7M_Set_exception_priority( int vector, int priority );

ARMV7M_Exception_handler _ARMV7M_Get_exception_handler( int index );

void _ARMV7M_Set_exception_handler(
  int index,
  ARMV7M_Exception_handler handler
);

/**
 * @brief ARMV7M set exception priority and handler.
 */
void _ARMV7M_Set_exception_priority_and_handler(
  int index,
  int priority,
  ARMV7M_Exception_handler handler
);

void _ARMV7M_Exception_default( void );

void _ARMV7M_Interrupt_service_enter( void );

void _ARMV7M_Interrupt_service_leave( void );

void _ARMV7M_Pendable_service_call( void );

void _ARMV7M_Supervisor_call( void );

void _ARMV7M_Clock_handler( void );

static inline uint32_t _ARMV7M_MPU_Get_region_size(uintptr_t size)
{
  if ((size & (size - 1)) == 0) {
    return ARMV7M_MPU_RASR_SIZE(30 - __builtin_clz(size));
  } else {
    return ARMV7M_MPU_RASR_SIZE(31 - __builtin_clz(size));
  }
}

static inline void _ARMV7M_MPU_Set_region(
  volatile ARMV7M_MPU *mpu,
  uint32_t region,
  uint32_t rasr,
  const void *begin,
  const void *end
)
{
  uintptr_t size;
  uint32_t rbar;

  RTEMS_OBFUSCATE_VARIABLE(begin);
  RTEMS_OBFUSCATE_VARIABLE(end);
  size = (uintptr_t) end - (uintptr_t) begin;

  if ( (uintptr_t) end > (uintptr_t) begin ) {
    rbar = (uintptr_t) begin | region | ARMV7M_MPU_RBAR_VALID;
    rasr |= _ARMV7M_MPU_Get_region_size(size);
  } else {
    rbar = ARMV7M_MPU_RBAR_VALID | region;
    rasr = 0;
  }

  mpu->rbar = rbar;
  mpu->rasr = rasr;
}

static inline void _ARMV7M_MPU_Disable_region(
  volatile ARMV7M_MPU *mpu,
  uint32_t region
)
{
  mpu->rbar = ARMV7M_MPU_RBAR_VALID | region;
  mpu->rasr = 0;
}

static inline void _ARMV7M_MPU_Setup(
  const ARMV7M_MPU_Region_config *cfg,
  size_t cfg_count
)
{
  volatile ARMV7M_MPU *mpu;
  volatile ARMV7M_SCB *scb;
  uint32_t region_count;
  uint32_t region;

  mpu = _ARMV7M_MPU;
  scb = _ARMV7M_SCB;

  mpu->ctrl = 0;

  _ARM_Data_synchronization_barrier();
  _ARM_Instruction_synchronization_barrier();

  region_count = ARMV7M_MPU_TYPE_DREGION_GET(mpu->type);

  _Assert(cfg_count <= region_count);

  for (region = 0; region < cfg_count; ++region) {
    _ARMV7M_MPU_Set_region(
      mpu,
      region,
      cfg[region].rasr,
      cfg[region].begin,
      cfg[region].end
    );
  }

  for (region = cfg_count; region < region_count; ++region) {
    _ARMV7M_MPU_Disable_region(mpu, region);
  }

  mpu->ctrl = ARMV7M_MPU_CTRL_ENABLE | ARMV7M_MPU_CTRL_PRIVDEFENA;
  scb->shcsr |= ARMV7M_SCB_SHCSR_MEMFAULTENA;

  _ARM_Data_synchronization_barrier();
  _ARM_Instruction_synchronization_barrier();
}

#endif /* ASM */

#endif /* ARM_MULTILIB_ARCH_V7M */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* RTEMS_SCORE_ARMV7M_H */