/** * * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries. * * \asf_license_start * * \page License * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the Licence at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * \asf_license_stop * */ /** @file cpu.h *MEC1701 CPU abstractions */ /** @defgroup cpu */ #ifndef _CPU_H #define _CPU_H #include #ifdef __cplusplus extern "C" { #endif #ifdef __CC_ARM /* Keil ARM MDK */ #ifndef UINT8_C #define UINT8_C(x) (unsigned char)(x) #endif #ifndef UINT16_C #define UINT16_C(x) (unsigned int)(x) #endif #ifndef UINT32_C #define UINT32_C(x) (unsigned long)(x) #endif #define USED __attribute__((used)) #define WEAK __attribute__((weak)) #define INLINE __inline #define NORETURN __declspec(noreturn) #define PACKED __packed #define CPU_GET_INTERRUPT_STATE() __get_PRIMASK() #define CPU_SET_INTERRUPT_STATE(x) __set_PRIMASK((x)) /* * Keil MDK intrisic __disable_irq() returns the value of MSR PRIMASK * before disabling interrupts. */ #define CPU_DISABLE_INTERRUPTS() __disable_irq() #define CPU_GET_DISABLE_INTERRUPTS(x) {(x) = __disable_irq();} #define CPU_RESTORE_INTERRUPTS(x) { if (!(x)) { __enable_irq(); } } #define CPU_ENABLE_INTERRUPTS() __enable_irq() #define CPU_NOP() __nop() #define CPU_WAIT_FOR_INTR() __wfi() #define CPU_REV(x) __rev(x) #define CPU_CLZ(x) __clz(x) #elif defined(__XC32_PART_SUPPORT_VERSION) /* Microchip XC32 compiler customized GCC */ #error "!!! FORCED BUILD ERROR: compiler.h XC32 support has not been implemented !!!" #elif defined(__GNUC__) && defined(__ARM_EABI__) /* GCC for ARM (arm-none-eabi-gcc) */ #include #include #ifndef __always_inline #define __always_inline inline __attribute__((always_inline)) #endif static __always_inline void __NOP_THUMB2(void) { __asm volatile ("nop"); } #define CPU_NOP() __NOP_THUMB2() static __always_inline void __WFI_THUMB2(void) { __asm volatile ("dsb"); __asm volatile ("isb"); __asm volatile ("wfi"); __asm volatile ("nop"); __asm volatile ("nop"); __asm volatile ("nop"); } #define CPU_WAIT_FOR_INTR() __WFI_THUMB2() /* We require user have ARM CMSIS header files available and configured * core_cmFunc.h includes inlines for global interrupt control. * For some reason, CMSIS __disable_irq for GCC does not return current PRIMASK * value. */ static __always_inline uint32_t __get_disable_irq(void) { uint32_t pri_mask; __asm volatile ( "\tmrs %0, primask\n" "\tcpsid i\n" "\tdsb\n" "\tisb\n" : "=r" (pri_mask) :: "memory" ); return pri_mask; } static __always_inline uint32_t __get_primask(void) { uint32_t pri_mask; __asm volatile ( "\tmrs %0, primask\n" "\tisb\n" : "=r" (pri_mask) :: "memory" ); return pri_mask; } static __always_inline void __enable_irqs(void) { __asm volatile ("cpsie i" : : : "memory"); } static __always_inline void __disable_irqs(void) { __asm volatile ( "\tcpsid i\n" "\tdsb\n" "\tisb\n" : : : "memory"); } #define CPU_GET_INTERRUPT_STATE() __get_primask() #define CPU_GET_DISABLE_INTERRUPTS(x) {(x) = __get_disable_irq();} #define CPU_RESTORE_INTERRUPTS(x) { if (!(x)) { __enable_irqs(); } } #define CPU_ENABLE_INTERRUPTS() __enable_irqs() #define CPU_DISABLE_INTERRUPTS() __disable_irqs() static __always_inline uint32_t __REV_THUMB2(uint32_t u32) { return __builtin_bswap32(u32); } #define CPU_REV(x) __REV_THUMB2(x) /* * __builtin_clz() will not be available if user compiles with built-ins disabled flag. */ #define CPU_CLZ(x) __builtin_clz(x) static inline __attribute__((always_inline, noreturn)) void CPU_JMP(uint32_t addr) { addr |= (1ul << 0); __asm volatile ( "\n\t" "\tBX %0 \n" "\tNOP \n" : /* no outputs */ :"r"(addr) :); while(1); } static __always_inline void write_read_back8(volatile uint8_t* addr, uint8_t val) { __asm__ __volatile__ ( "\n\t" "strb %1, [%0] \n\t" "ldrb %1, [%0] \n\t" : /* No outputs */ : "r" (addr), "r" (val) : "memory" ); } static __always_inline void write_read_back16(volatile uint16_t* addr, uint16_t val) { __asm__ __volatile__ ( "\n\t" "strh %1, [%0] \n\t" "ldrh %1, [%0] \n\t" : /* No outputs */ : "r" (addr), "r" (val) : "memory" ); } static __always_inline void write_read_back32(volatile uint32_t* addr, uint32_t val) { __asm__ __volatile__ ( "\n\t" "str %1, [%0] \n\t" "ldr %1, [%0] \n\t" : /* No outputs */ : "r" (addr), "r" (val) : "memory" ); } #else /* Unknown compiler */ #error "!!! FORCED BUILD ERROR: cpu.h Unknown compiler !!!" #endif #ifdef __cplusplus } #endif #endif /* #ifndef _CPU_H */ /** @} */