1 /** 2 * 3 * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries. 4 * 5 * \asf_license_start 6 * 7 * \page License 8 * 9 * SPDX-License-Identifier: Apache-2.0 10 * 11 * Licensed under the Apache License, Version 2.0 (the "License"); you may 12 * not use this file except in compliance with the License. 13 * You may obtain a copy of the Licence at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, software 18 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 19 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 * See the License for the specific language governing permissions and 21 * limitations under the License. 22 * 23 * \asf_license_stop 24 * 25 */ 26 27 /** @file cpu.h 28 *MEC1701 CPU abstractions 29 */ 30 /** @defgroup cpu 31 */ 32 33 34 #ifndef _CPU_H 35 #define _CPU_H 36 37 #include <stdint.h> 38 39 #ifdef __cplusplus 40 extern "C" { 41 #endif 42 43 44 #ifdef __CC_ARM /* Keil ARM MDK */ 45 46 #ifndef UINT8_C 47 #define UINT8_C(x) (unsigned char)(x) 48 #endif 49 50 #ifndef UINT16_C 51 #define UINT16_C(x) (unsigned int)(x) 52 #endif 53 54 #ifndef UINT32_C 55 #define UINT32_C(x) (unsigned long)(x) 56 #endif 57 58 #define USED __attribute__((used)) 59 #define WEAK __attribute__((weak)) 60 #define INLINE __inline 61 #define NORETURN __declspec(noreturn) 62 #define PACKED __packed 63 #define CPU_GET_INTERRUPT_STATE() __get_PRIMASK() 64 #define CPU_SET_INTERRUPT_STATE(x) __set_PRIMASK((x)) 65 66 /* 67 * Keil MDK intrisic __disable_irq() returns the value of MSR PRIMASK 68 * before disabling interrupts. 69 */ 70 #define CPU_DISABLE_INTERRUPTS() __disable_irq() 71 #define CPU_GET_DISABLE_INTERRUPTS(x) {(x) = __disable_irq();} 72 #define CPU_RESTORE_INTERRUPTS(x) { if (!(x)) { __enable_irq(); } } 73 #define CPU_ENABLE_INTERRUPTS() __enable_irq() 74 75 #define CPU_NOP() __nop() 76 #define CPU_WAIT_FOR_INTR() __wfi() 77 78 #define CPU_REV(x) __rev(x) 79 80 #define CPU_CLZ(x) __clz(x) 81 82 #elif defined(__XC32_PART_SUPPORT_VERSION) /* Microchip XC32 compiler customized GCC */ 83 84 #error "!!! FORCED BUILD ERROR: compiler.h XC32 support has not been implemented !!!" 85 86 #elif defined(__GNUC__) && defined(__ARM_EABI__) /* GCC for ARM (arm-none-eabi-gcc) */ 87 88 #include <stdint.h> 89 #include <stddef.h> 90 91 #ifndef __always_inline 92 #define __always_inline inline __attribute__((always_inline)) 93 #endif 94 95 static __always_inline void __NOP_THUMB2(void) 96 { 97 __asm volatile ("nop"); 98 } 99 100 #define CPU_NOP() __NOP_THUMB2() 101 102 static __always_inline void __WFI_THUMB2(void) 103 { 104 __asm volatile ("dsb"); 105 __asm volatile ("isb"); 106 __asm volatile ("wfi"); 107 __asm volatile ("nop"); 108 __asm volatile ("nop"); 109 __asm volatile ("nop"); 110 } 111 112 #define CPU_WAIT_FOR_INTR() __WFI_THUMB2() 113 114 /* We require user have ARM CMSIS header files available and configured 115 * core_cmFunc.h includes inlines for global interrupt control. 116 * For some reason, CMSIS __disable_irq for GCC does not return current PRIMASK 117 * value. */ 118 119 static __always_inline uint32_t __get_disable_irq(void) 120 { 121 uint32_t pri_mask; 122 123 __asm volatile ( 124 "\tmrs %0, primask\n" 125 "\tcpsid i\n" 126 "\tdsb\n" 127 "\tisb\n" 128 : "=r" (pri_mask) :: "memory" 129 ); 130 return pri_mask; 131 } 132 133 static __always_inline uint32_t __get_primask(void) 134 { 135 uint32_t pri_mask; 136 137 __asm volatile ( 138 "\tmrs %0, primask\n" 139 "\tisb\n" 140 : "=r" (pri_mask) :: "memory" 141 ); 142 return pri_mask; 143 } 144 145 static __always_inline void __enable_irqs(void) 146 { 147 __asm volatile ("cpsie i" : : : "memory"); 148 } 149 150 static __always_inline void __disable_irqs(void) 151 { 152 __asm volatile ( 153 "\tcpsid i\n" 154 "\tdsb\n" 155 "\tisb\n" : : : "memory"); 156 } 157 158 159 #define CPU_GET_INTERRUPT_STATE() __get_primask() 160 #define CPU_GET_DISABLE_INTERRUPTS(x) {(x) = __get_disable_irq();} 161 #define CPU_RESTORE_INTERRUPTS(x) { if (!(x)) { __enable_irqs(); } } 162 #define CPU_ENABLE_INTERRUPTS() __enable_irqs() 163 #define CPU_DISABLE_INTERRUPTS() __disable_irqs() 164 165 166 static __always_inline uint32_t __REV_THUMB2(uint32_t u32) 167 { 168 return __builtin_bswap32(u32); 169 } 170 171 #define CPU_REV(x) __REV_THUMB2(x) 172 173 /* 174 * __builtin_clz() will not be available if user compiles with built-ins disabled flag. 175 */ 176 #define CPU_CLZ(x) __builtin_clz(x) 177 178 static inline __attribute__((always_inline, noreturn)) void CPU_JMP(uint32_t addr) 179 { 180 addr |= (1ul << 0); 181 182 __asm volatile ( 183 "\n\t" 184 "\tBX %0 \n" 185 "\tNOP \n" 186 : /* no outputs */ 187 :"r"(addr) 188 :); 189 while(1); 190 } 191 192 static __always_inline void write_read_back8(volatile uint8_t* addr, uint8_t val) 193 { 194 __asm__ __volatile__ ( 195 "\n\t" 196 "strb %1, [%0] \n\t" 197 "ldrb %1, [%0] \n\t" 198 : /* No outputs */ 199 : "r" (addr), "r" (val) 200 : "memory" 201 ); 202 } 203 204 static __always_inline void write_read_back16(volatile uint16_t* addr, uint16_t val) 205 { 206 __asm__ __volatile__ ( 207 "\n\t" 208 "strh %1, [%0] \n\t" 209 "ldrh %1, [%0] \n\t" 210 : /* No outputs */ 211 : "r" (addr), "r" (val) 212 : "memory" 213 ); 214 } 215 216 static __always_inline void write_read_back32(volatile uint32_t* addr, uint32_t val) 217 { 218 __asm__ __volatile__ ( 219 "\n\t" 220 "str %1, [%0] \n\t" 221 "ldr %1, [%0] \n\t" 222 : /* No outputs */ 223 : "r" (addr), "r" (val) 224 : "memory" 225 ); 226 } 227 228 #else /* Unknown compiler */ 229 230 #error "!!! FORCED BUILD ERROR: cpu.h Unknown compiler !!!" 231 232 #endif 233 234 #ifdef __cplusplus 235 } 236 #endif 237 238 #endif /* #ifndef _CPU_H */ 239 /** @} 240 */ 241