1 /******************************************************************************
2 * @file cachel1_armv7.h
3 * @brief CMSIS Level 1 Cache API for Armv7-M and later
6 ******************************************************************************/
8 * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
10 * SPDX-License-Identifier: Apache-2.0
12 * Licensed under the Apache License, Version 2.0 (the License); you may
13 * not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
16 * www.apache.org/licenses/LICENSE-2.0
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
20 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
25 #if defined ( __ICCARM__ )
26 #pragma system_include /* treat file as system include file for MISRA check */
27 #elif defined (__clang__)
28 #pragma clang system_header /* treat file as system include file */
31 #ifndef ARM_CACHEL1_ARMV7_H
32 #define ARM_CACHEL1_ARMV7_H
35 \ingroup CMSIS_Core_FunctionInterface
36 \defgroup CMSIS_Core_CacheFunctions Cache Functions
37 \brief Functions that configure Instruction and Data cache.
41 /* Cache Size ID Register Macros */
42 #define CCSIDR_WAYS(x) (((x) & SCB_CCSIDR_ASSOCIATIVITY_Msk) >> SCB_CCSIDR_ASSOCIATIVITY_Pos)
43 #define CCSIDR_SETS(x) (((x) & SCB_CCSIDR_NUMSETS_Msk ) >> SCB_CCSIDR_NUMSETS_Pos )
45 #ifndef __SCB_DCACHE_LINE_SIZE
46 #define __SCB_DCACHE_LINE_SIZE 32U /*!< Cortex-M7 cache line size is fixed to 32 bytes (8 words). See also register SCB_CCSIDR */
49 #ifndef __SCB_ICACHE_LINE_SIZE
50 #define __SCB_ICACHE_LINE_SIZE 32U /*!< Cortex-M7 cache line size is fixed to 32 bytes (8 words). See also register SCB_CCSIDR */
55 \details Turns on I-Cache
57 __STATIC_FORCEINLINE void SCB_EnableICache (void)
59 #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
60 if (SCB->CCR & SCB_CCR_IC_Msk) return; /* return if ICache is already enabled */
64 SCB->ICIALLU = 0UL; /* invalidate I-Cache */
67 SCB->CCR |= (uint32_t)SCB_CCR_IC_Msk; /* enable I-Cache */
75 \brief Disable I-Cache
76 \details Turns off I-Cache
78 __STATIC_FORCEINLINE void SCB_DisableICache (void)
80 #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
83 SCB->CCR &= ~(uint32_t)SCB_CCR_IC_Msk; /* disable I-Cache */
84 SCB->ICIALLU = 0UL; /* invalidate I-Cache */
92 \brief Invalidate I-Cache
93 \details Invalidates I-Cache
95 __STATIC_FORCEINLINE void SCB_InvalidateICache (void)
97 #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
108 \brief I-Cache Invalidate by address
109 \details Invalidates I-Cache for the given address.
110 I-Cache is invalidated starting from a 32 byte aligned address in 32 byte granularity.
111 I-Cache memory blocks which are part of given address + given size are invalidated.
112 \param[in] addr address
113 \param[in] isize size of memory block (in number of bytes)
115 __STATIC_FORCEINLINE void SCB_InvalidateICache_by_Addr (volatile void *addr, int32_t isize)
117 #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
119 int32_t op_size = isize + (((uint32_t)addr) & (__SCB_ICACHE_LINE_SIZE - 1U));
120 uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_ICACHE_LINE_SIZE - 1U) */;
125 SCB->ICIMVAU = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */
126 op_addr += __SCB_ICACHE_LINE_SIZE;
127 op_size -= __SCB_ICACHE_LINE_SIZE;
128 } while ( op_size > 0 );
138 \brief Enable D-Cache
139 \details Turns on D-Cache
141 __STATIC_FORCEINLINE void SCB_EnableDCache (void)
143 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
148 if (SCB->CCR & SCB_CCR_DC_Msk) return; /* return if DCache is already enabled */
150 SCB->CSSELR = 0U; /* select Level 1 data cache */
153 ccsidr = SCB->CCSIDR;
155 /* invalidate D-Cache */
156 sets = (uint32_t)(CCSIDR_SETS(ccsidr));
158 ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
160 SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
161 ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk) );
162 #if defined ( __CC_ARM )
163 __schedule_barrier();
165 } while (ways-- != 0U);
166 } while(sets-- != 0U);
169 SCB->CCR |= (uint32_t)SCB_CCR_DC_Msk; /* enable D-Cache */
178 \brief Disable D-Cache
179 \details Turns off D-Cache
181 __STATIC_FORCEINLINE void SCB_DisableDCache (void)
183 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
189 #if ((defined(__GNUC__) || defined(__clang__)) && !defined(__OPTIMIZE__))
190 __ALIGNED(__SCB_DCACHE_LINE_SIZE)
194 SCB->CSSELR = 0U; /* select Level 1 data cache */
197 SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk; /* disable D-Cache */
200 #if !defined(__OPTIMIZE__)
202 * For the endless loop issue with no optimization builds.
203 * More details, see https://github.com/ARM-software/CMSIS_5/issues/620
205 * The issue only happens when local variables are in stack. If
206 * local variables are saved in general purpose register, then the function
209 * When local variables are in stack, after disabling the cache, flush the
210 * local variables cache line for data consistency.
212 /* Clean and invalidate the local variable cache. */
213 #if defined(__ICCARM__)
214 /* As we can't align the stack to the cache line size, invalidate each of the variables */
215 SCB->DCCIMVAC = (uint32_t)&locals.sets;
216 SCB->DCCIMVAC = (uint32_t)&locals.ways;
217 SCB->DCCIMVAC = (uint32_t)&locals.ccsidr;
219 SCB->DCCIMVAC = (uint32_t)&locals;
225 locals.ccsidr = SCB->CCSIDR;
226 /* clean & invalidate D-Cache */
227 locals.sets = (uint32_t)(CCSIDR_SETS(locals.ccsidr));
229 locals.ways = (uint32_t)(CCSIDR_WAYS(locals.ccsidr));
231 SCB->DCCISW = (((locals.sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
232 ((locals.ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk) );
233 #if defined ( __CC_ARM )
234 __schedule_barrier();
236 } while (locals.ways-- != 0U);
237 } while(locals.sets-- != 0U);
246 \brief Invalidate D-Cache
247 \details Invalidates D-Cache
249 __STATIC_FORCEINLINE void SCB_InvalidateDCache (void)
251 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
256 SCB->CSSELR = 0U; /* select Level 1 data cache */
259 ccsidr = SCB->CCSIDR;
261 /* invalidate D-Cache */
262 sets = (uint32_t)(CCSIDR_SETS(ccsidr));
264 ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
266 SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
267 ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk) );
268 #if defined ( __CC_ARM )
269 __schedule_barrier();
271 } while (ways-- != 0U);
272 } while(sets-- != 0U);
282 \details Cleans D-Cache
284 __STATIC_FORCEINLINE void SCB_CleanDCache (void)
286 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
291 SCB->CSSELR = 0U; /* select Level 1 data cache */
294 ccsidr = SCB->CCSIDR;
297 sets = (uint32_t)(CCSIDR_SETS(ccsidr));
299 ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
301 SCB->DCCSW = (((sets << SCB_DCCSW_SET_Pos) & SCB_DCCSW_SET_Msk) |
302 ((ways << SCB_DCCSW_WAY_Pos) & SCB_DCCSW_WAY_Msk) );
303 #if defined ( __CC_ARM )
304 __schedule_barrier();
306 } while (ways-- != 0U);
307 } while(sets-- != 0U);
316 \brief Clean & Invalidate D-Cache
317 \details Cleans and Invalidates D-Cache
319 __STATIC_FORCEINLINE void SCB_CleanInvalidateDCache (void)
321 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
326 SCB->CSSELR = 0U; /* select Level 1 data cache */
329 ccsidr = SCB->CCSIDR;
331 /* clean & invalidate D-Cache */
332 sets = (uint32_t)(CCSIDR_SETS(ccsidr));
334 ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
336 SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
337 ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk) );
338 #if defined ( __CC_ARM )
339 __schedule_barrier();
341 } while (ways-- != 0U);
342 } while(sets-- != 0U);
351 \brief D-Cache Invalidate by address
352 \details Invalidates D-Cache for the given address.
353 D-Cache is invalidated starting from a 32 byte aligned address in 32 byte granularity.
354 D-Cache memory blocks which are part of given address + given size are invalidated.
355 \param[in] addr address
356 \param[in] dsize size of memory block (in number of bytes)
358 __STATIC_FORCEINLINE void SCB_InvalidateDCache_by_Addr (volatile void *addr, int32_t dsize)
360 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
362 int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
363 uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
368 SCB->DCIMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */
369 op_addr += __SCB_DCACHE_LINE_SIZE;
370 op_size -= __SCB_DCACHE_LINE_SIZE;
371 } while ( op_size > 0 );
381 \brief D-Cache Clean by address
382 \details Cleans D-Cache for the given address
383 D-Cache is cleaned starting from a 32 byte aligned address in 32 byte granularity.
384 D-Cache memory blocks which are part of given address + given size are cleaned.
385 \param[in] addr address
386 \param[in] dsize size of memory block (in number of bytes)
388 __STATIC_FORCEINLINE void SCB_CleanDCache_by_Addr (volatile void *addr, int32_t dsize)
390 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
392 int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
393 uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
398 SCB->DCCMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */
399 op_addr += __SCB_DCACHE_LINE_SIZE;
400 op_size -= __SCB_DCACHE_LINE_SIZE;
401 } while ( op_size > 0 );
411 \brief D-Cache Clean and Invalidate by address
412 \details Cleans and invalidates D_Cache for the given address
413 D-Cache is cleaned and invalidated starting from a 32 byte aligned address in 32 byte granularity.
414 D-Cache memory blocks which are part of given address + given size are cleaned and invalidated.
415 \param[in] addr address (aligned to 32-byte boundary)
416 \param[in] dsize size of memory block (in number of bytes)
418 __STATIC_FORCEINLINE void SCB_CleanInvalidateDCache_by_Addr (volatile void *addr, int32_t dsize)
420 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
422 int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
423 uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
428 SCB->DCCIMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */
429 op_addr += __SCB_DCACHE_LINE_SIZE;
430 op_size -= __SCB_DCACHE_LINE_SIZE;
431 } while ( op_size > 0 );
439 /*@} end of CMSIS_Core_CacheFunctions */
441 #endif /* ARM_CACHEL1_ARMV7_H */