1 /******************************************************************************
2 * @file cachel1_armv7.h
3 * @brief CMSIS Level 1 Cache API for Armv7-M and later
4 * @version V1.0.1
5 * @date 19. April 2021
6 ******************************************************************************/
7 /*
8 * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 *
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
15 *
16 * www.apache.org/licenses/LICENSE-2.0
17 *
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.
23 */
24
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 */
29 #endif
30
31 #ifndef ARM_CACHEL1_ARMV7_H
32 #define ARM_CACHEL1_ARMV7_H
33
34 /**
35 \ingroup CMSIS_Core_FunctionInterface
36 \defgroup CMSIS_Core_CacheFunctions Cache Functions
37 \brief Functions that configure Instruction and Data cache.
38 @{
39 */
40
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 )
44
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 */
47 #endif
48
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 */
51 #endif
52
53 /**
54 \brief Enable I-Cache
55 \details Turns on I-Cache
56 */
SCB_EnableICache(void)57 __STATIC_FORCEINLINE void SCB_EnableICache (void)
58 {
59 #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
60 if (SCB->CCR & SCB_CCR_IC_Msk) return; /* return if ICache is already enabled */
61
62 __DSB();
63 __ISB();
64 SCB->ICIALLU = 0UL; /* invalidate I-Cache */
65 __DSB();
66 __ISB();
67 SCB->CCR |= (uint32_t)SCB_CCR_IC_Msk; /* enable I-Cache */
68 __DSB();
69 __ISB();
70 #endif
71 }
72
73
74 /**
75 \brief Disable I-Cache
76 \details Turns off I-Cache
77 */
SCB_DisableICache(void)78 __STATIC_FORCEINLINE void SCB_DisableICache (void)
79 {
80 #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
81 __DSB();
82 __ISB();
83 SCB->CCR &= ~(uint32_t)SCB_CCR_IC_Msk; /* disable I-Cache */
84 SCB->ICIALLU = 0UL; /* invalidate I-Cache */
85 __DSB();
86 __ISB();
87 #endif
88 }
89
90
91 /**
92 \brief Invalidate I-Cache
93 \details Invalidates I-Cache
94 */
SCB_InvalidateICache(void)95 __STATIC_FORCEINLINE void SCB_InvalidateICache (void)
96 {
97 #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
98 __DSB();
99 __ISB();
100 SCB->ICIALLU = 0UL;
101 __DSB();
102 __ISB();
103 #endif
104 }
105
106
107 /**
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)
114 */
SCB_InvalidateICache_by_Addr(volatile void * addr,int32_t isize)115 __STATIC_FORCEINLINE void SCB_InvalidateICache_by_Addr (volatile void *addr, int32_t isize)
116 {
117 #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
118 if ( isize > 0 ) {
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) */;
121
122 __DSB();
123
124 do {
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 );
129
130 __DSB();
131 __ISB();
132 }
133 #endif
134 }
135
136
137 /**
138 \brief Enable D-Cache
139 \details Turns on D-Cache
140 */
SCB_EnableDCache(void)141 __STATIC_FORCEINLINE void SCB_EnableDCache (void)
142 {
143 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
144 uint32_t ccsidr;
145 uint32_t sets;
146 uint32_t ways;
147
148 if (SCB->CCR & SCB_CCR_DC_Msk) return; /* return if DCache is already enabled */
149
150 SCB->CSSELR = 0U; /* select Level 1 data cache */
151 __DSB();
152
153 ccsidr = SCB->CCSIDR;
154
155 /* invalidate D-Cache */
156 sets = (uint32_t)(CCSIDR_SETS(ccsidr));
157 do {
158 ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
159 do {
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();
164 #endif
165 } while (ways-- != 0U);
166 } while(sets-- != 0U);
167 __DSB();
168
169 SCB->CCR |= (uint32_t)SCB_CCR_DC_Msk; /* enable D-Cache */
170
171 __DSB();
172 __ISB();
173 #endif
174 }
175
176
177 /**
178 \brief Disable D-Cache
179 \details Turns off D-Cache
180 */
SCB_DisableDCache(void)181 __STATIC_FORCEINLINE void SCB_DisableDCache (void)
182 {
183 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
184 uint32_t ccsidr;
185 uint32_t sets;
186 uint32_t ways;
187
188 SCB->CSSELR = 0U; /* select Level 1 data cache */
189 __DSB();
190
191 SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk; /* disable D-Cache */
192 __DSB();
193
194 /*
195 * For the endless loop issue with GCC O0.
196 * More details, see https://github.com/ARM-software/CMSIS_5/issues/620
197 *
198 * The issue only happens when local variables are in stack (GCC O0). If
199 * local variables are saved in general purpose register, then the function
200 * is OK.
201 *
202 * When local variables are in stack, after disabling the cache, flush the
203 * local variables cache line for data consistency.
204 */
205 /* Clean and invalidate the local variable cache. */
206 SCB->DCCIMVAC = (uint32_t)(&sets);
207 SCB->DCCIMVAC = (uint32_t)(&ways);
208 SCB->DCCIMVAC = (uint32_t)(&ccsidr);
209 __DSB();
210 __ISB();
211
212 ccsidr = SCB->CCSIDR;
213
214 /* clean & invalidate D-Cache */
215 sets = (uint32_t)(CCSIDR_SETS(ccsidr));
216 do {
217 ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
218 do {
219 SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
220 ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk) );
221 #if defined ( __CC_ARM )
222 __schedule_barrier();
223 #endif
224 } while (ways-- != 0U);
225 } while(sets-- != 0U);
226
227 __DSB();
228 __ISB();
229 #endif
230 }
231
232
233 /**
234 \brief Invalidate D-Cache
235 \details Invalidates D-Cache
236 */
SCB_InvalidateDCache(void)237 __STATIC_FORCEINLINE void SCB_InvalidateDCache (void)
238 {
239 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
240 uint32_t ccsidr;
241 uint32_t sets;
242 uint32_t ways;
243
244 SCB->CSSELR = 0U; /* select Level 1 data cache */
245 __DSB();
246
247 ccsidr = SCB->CCSIDR;
248
249 /* invalidate D-Cache */
250 sets = (uint32_t)(CCSIDR_SETS(ccsidr));
251 do {
252 ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
253 do {
254 SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
255 ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk) );
256 #if defined ( __CC_ARM )
257 __schedule_barrier();
258 #endif
259 } while (ways-- != 0U);
260 } while(sets-- != 0U);
261
262 __DSB();
263 __ISB();
264 #endif
265 }
266
267
268 /**
269 \brief Clean D-Cache
270 \details Cleans D-Cache
271 */
SCB_CleanDCache(void)272 __STATIC_FORCEINLINE void SCB_CleanDCache (void)
273 {
274 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
275 uint32_t ccsidr;
276 uint32_t sets;
277 uint32_t ways;
278
279 SCB->CSSELR = 0U; /* select Level 1 data cache */
280 __DSB();
281
282 ccsidr = SCB->CCSIDR;
283
284 /* clean D-Cache */
285 sets = (uint32_t)(CCSIDR_SETS(ccsidr));
286 do {
287 ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
288 do {
289 SCB->DCCSW = (((sets << SCB_DCCSW_SET_Pos) & SCB_DCCSW_SET_Msk) |
290 ((ways << SCB_DCCSW_WAY_Pos) & SCB_DCCSW_WAY_Msk) );
291 #if defined ( __CC_ARM )
292 __schedule_barrier();
293 #endif
294 } while (ways-- != 0U);
295 } while(sets-- != 0U);
296
297 __DSB();
298 __ISB();
299 #endif
300 }
301
302
303 /**
304 \brief Clean & Invalidate D-Cache
305 \details Cleans and Invalidates D-Cache
306 */
SCB_CleanInvalidateDCache(void)307 __STATIC_FORCEINLINE void SCB_CleanInvalidateDCache (void)
308 {
309 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
310 uint32_t ccsidr;
311 uint32_t sets;
312 uint32_t ways;
313
314 SCB->CSSELR = 0U; /* select Level 1 data cache */
315 __DSB();
316
317 ccsidr = SCB->CCSIDR;
318
319 /* clean & invalidate D-Cache */
320 sets = (uint32_t)(CCSIDR_SETS(ccsidr));
321 do {
322 ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
323 do {
324 SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
325 ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk) );
326 #if defined ( __CC_ARM )
327 __schedule_barrier();
328 #endif
329 } while (ways-- != 0U);
330 } while(sets-- != 0U);
331
332 __DSB();
333 __ISB();
334 #endif
335 }
336
337
338 /**
339 \brief D-Cache Invalidate by address
340 \details Invalidates D-Cache for the given address.
341 D-Cache is invalidated starting from a 32 byte aligned address in 32 byte granularity.
342 D-Cache memory blocks which are part of given address + given size are invalidated.
343 \param[in] addr address
344 \param[in] dsize size of memory block (in number of bytes)
345 */
SCB_InvalidateDCache_by_Addr(volatile void * addr,int32_t dsize)346 __STATIC_FORCEINLINE void SCB_InvalidateDCache_by_Addr (volatile void *addr, int32_t dsize)
347 {
348 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
349 if ( dsize > 0 ) {
350 int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
351 uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
352
353 __DSB();
354
355 do {
356 SCB->DCIMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */
357 op_addr += __SCB_DCACHE_LINE_SIZE;
358 op_size -= __SCB_DCACHE_LINE_SIZE;
359 } while ( op_size > 0 );
360
361 __DSB();
362 __ISB();
363 }
364 #endif
365 }
366
367
368 /**
369 \brief D-Cache Clean by address
370 \details Cleans D-Cache for the given address
371 D-Cache is cleaned starting from a 32 byte aligned address in 32 byte granularity.
372 D-Cache memory blocks which are part of given address + given size are cleaned.
373 \param[in] addr address
374 \param[in] dsize size of memory block (in number of bytes)
375 */
SCB_CleanDCache_by_Addr(volatile void * addr,int32_t dsize)376 __STATIC_FORCEINLINE void SCB_CleanDCache_by_Addr (volatile void *addr, int32_t dsize)
377 {
378 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
379 if ( dsize > 0 ) {
380 int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
381 uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
382
383 __DSB();
384
385 do {
386 SCB->DCCMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */
387 op_addr += __SCB_DCACHE_LINE_SIZE;
388 op_size -= __SCB_DCACHE_LINE_SIZE;
389 } while ( op_size > 0 );
390
391 __DSB();
392 __ISB();
393 }
394 #endif
395 }
396
397
398 /**
399 \brief D-Cache Clean and Invalidate by address
400 \details Cleans and invalidates D_Cache for the given address
401 D-Cache is cleaned and invalidated starting from a 32 byte aligned address in 32 byte granularity.
402 D-Cache memory blocks which are part of given address + given size are cleaned and invalidated.
403 \param[in] addr address (aligned to 32-byte boundary)
404 \param[in] dsize size of memory block (in number of bytes)
405 */
SCB_CleanInvalidateDCache_by_Addr(volatile void * addr,int32_t dsize)406 __STATIC_FORCEINLINE void SCB_CleanInvalidateDCache_by_Addr (volatile void *addr, int32_t dsize)
407 {
408 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
409 if ( dsize > 0 ) {
410 int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
411 uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
412
413 __DSB();
414
415 do {
416 SCB->DCCIMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */
417 op_addr += __SCB_DCACHE_LINE_SIZE;
418 op_size -= __SCB_DCACHE_LINE_SIZE;
419 } while ( op_size > 0 );
420
421 __DSB();
422 __ISB();
423 }
424 #endif
425 }
426
427 /*@} end of CMSIS_Core_CacheFunctions */
428
429 #endif /* ARM_CACHEL1_ARMV7_H */
430