Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:02

0001 /******************************************************************************
0002  * @file     cachel1_armv7.h
0003  * @brief    CMSIS Level 1 Cache API for Armv7-M and later
0004  * @version  V1.0.3
0005  * @date     17. March 2023
0006  ******************************************************************************/
0007 /*
0008  * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
0009  *
0010  * SPDX-License-Identifier: Apache-2.0
0011  *
0012  * Licensed under the Apache License, Version 2.0 (the License); you may
0013  * not use this file except in compliance with the License.
0014  * You may obtain a copy of the License at
0015  *
0016  * www.apache.org/licenses/LICENSE-2.0
0017  *
0018  * Unless required by applicable law or agreed to in writing, software
0019  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
0020  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0021  * See the License for the specific language governing permissions and
0022  * limitations under the License.
0023  */
0024 
0025 #if   defined ( __ICCARM__ )
0026   #pragma system_include         /* treat file as system include file for MISRA check */
0027 #elif defined (__clang__)
0028   #pragma clang system_header    /* treat file as system include file */
0029 #endif
0030 
0031 #ifndef ARM_CACHEL1_ARMV7_H
0032 #define ARM_CACHEL1_ARMV7_H
0033 
0034 /**
0035   \ingroup  CMSIS_Core_FunctionInterface
0036   \defgroup CMSIS_Core_CacheFunctions Cache Functions
0037   \brief    Functions that configure Instruction and Data cache.
0038   @{
0039  */
0040 
0041 /* Cache Size ID Register Macros */
0042 #define CCSIDR_WAYS(x)         (((x) & SCB_CCSIDR_ASSOCIATIVITY_Msk) >> SCB_CCSIDR_ASSOCIATIVITY_Pos)
0043 #define CCSIDR_SETS(x)         (((x) & SCB_CCSIDR_NUMSETS_Msk      ) >> SCB_CCSIDR_NUMSETS_Pos      )
0044 
0045 #ifndef __SCB_DCACHE_LINE_SIZE
0046 #define __SCB_DCACHE_LINE_SIZE  32U /*!< Cortex-M7 cache line size is fixed to 32 bytes (8 words). See also register SCB_CCSIDR */
0047 #endif
0048 
0049 #ifndef __SCB_ICACHE_LINE_SIZE
0050 #define __SCB_ICACHE_LINE_SIZE  32U /*!< Cortex-M7 cache line size is fixed to 32 bytes (8 words). See also register SCB_CCSIDR */
0051 #endif
0052 
0053 /**
0054   \brief   Enable I-Cache
0055   \details Turns on I-Cache
0056   */
0057 __STATIC_FORCEINLINE void SCB_EnableICache (void)
0058 {
0059   #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
0060     if (SCB->CCR & SCB_CCR_IC_Msk) return;  /* return if ICache is already enabled */
0061 
0062     __DSB();
0063     __ISB();
0064     SCB->ICIALLU = 0UL;                     /* invalidate I-Cache */
0065     __DSB();
0066     __ISB();
0067     SCB->CCR |=  (uint32_t)SCB_CCR_IC_Msk;  /* enable I-Cache */
0068     __DSB();
0069     __ISB();
0070   #endif
0071 }
0072 
0073 
0074 /**
0075   \brief   Disable I-Cache
0076   \details Turns off I-Cache
0077   */
0078 __STATIC_FORCEINLINE void SCB_DisableICache (void)
0079 {
0080   #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
0081     __DSB();
0082     __ISB();
0083     SCB->CCR &= ~(uint32_t)SCB_CCR_IC_Msk;  /* disable I-Cache */
0084     SCB->ICIALLU = 0UL;                     /* invalidate I-Cache */
0085     __DSB();
0086     __ISB();
0087   #endif
0088 }
0089 
0090 
0091 /**
0092   \brief   Invalidate I-Cache
0093   \details Invalidates I-Cache
0094   */
0095 __STATIC_FORCEINLINE void SCB_InvalidateICache (void)
0096 {
0097   #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
0098     __DSB();
0099     __ISB();
0100     SCB->ICIALLU = 0UL;
0101     __DSB();
0102     __ISB();
0103   #endif
0104 }
0105 
0106 
0107 /**
0108   \brief   I-Cache Invalidate by address
0109   \details Invalidates I-Cache for the given address.
0110            I-Cache is invalidated starting from a 32 byte aligned address in 32 byte granularity.
0111            I-Cache memory blocks which are part of given address + given size are invalidated.
0112   \param[in]   addr    address
0113   \param[in]   isize   size of memory block (in number of bytes)
0114 */
0115 __STATIC_FORCEINLINE void SCB_InvalidateICache_by_Addr (volatile void *addr, int32_t isize)
0116 {
0117   #if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
0118     if ( isize > 0 ) {
0119        int32_t op_size = isize + (((uint32_t)addr) & (__SCB_ICACHE_LINE_SIZE - 1U));
0120       uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_ICACHE_LINE_SIZE - 1U) */;
0121 
0122       __DSB();
0123 
0124       do {
0125         SCB->ICIMVAU = op_addr;             /* register accepts only 32byte aligned values, only bits 31..5 are valid */
0126         op_addr += __SCB_ICACHE_LINE_SIZE;
0127         op_size -= __SCB_ICACHE_LINE_SIZE;
0128       } while ( op_size > 0 );
0129 
0130       __DSB();
0131       __ISB();
0132     }
0133   #endif
0134 }
0135 
0136 
0137 /**
0138   \brief   Enable D-Cache
0139   \details Turns on D-Cache
0140   */
0141 __STATIC_FORCEINLINE void SCB_EnableDCache (void)
0142 {
0143   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
0144     uint32_t ccsidr;
0145     uint32_t sets;
0146     uint32_t ways;
0147 
0148     if (SCB->CCR & SCB_CCR_DC_Msk) return;  /* return if DCache is already enabled */
0149 
0150     SCB->CSSELR = 0U;                       /* select Level 1 data cache */
0151     __DSB();
0152 
0153     ccsidr = SCB->CCSIDR;
0154 
0155                                             /* invalidate D-Cache */
0156     sets = (uint32_t)(CCSIDR_SETS(ccsidr));
0157     do {
0158       ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
0159       do {
0160         SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
0161                       ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk)  );
0162         #if defined ( __CC_ARM )
0163           __schedule_barrier();
0164         #endif
0165       } while (ways-- != 0U);
0166     } while(sets-- != 0U);
0167     __DSB();
0168 
0169     SCB->CCR |=  (uint32_t)SCB_CCR_DC_Msk;  /* enable D-Cache */
0170 
0171     __DSB();
0172     __ISB();
0173   #endif
0174 }
0175 
0176 
0177 /**
0178   \brief   Disable D-Cache
0179   \details Turns off D-Cache
0180   */
0181 __STATIC_FORCEINLINE void SCB_DisableDCache (void)
0182 {
0183   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
0184     struct {
0185       uint32_t ccsidr;
0186       uint32_t sets;
0187       uint32_t ways;
0188     } locals
0189     #if ((defined(__GNUC__) || defined(__clang__)) && !defined(__OPTIMIZE__))
0190        __ALIGNED(__SCB_DCACHE_LINE_SIZE)
0191     #endif
0192     ;
0193 
0194     SCB->CSSELR = 0U;                       /* select Level 1 data cache */
0195     __DSB();
0196 
0197     SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk;  /* disable D-Cache */
0198     __DSB();
0199 
0200     #if !defined(__OPTIMIZE__)
0201       /*
0202        * For the endless loop issue with no optimization builds.
0203        * More details, see https://github.com/ARM-software/CMSIS_5/issues/620
0204        *
0205        * The issue only happens when local variables are in stack. If
0206        * local variables are saved in general purpose register, then the function
0207        * is OK.
0208        *
0209        * When local variables are in stack, after disabling the cache, flush the
0210        * local variables cache line for data consistency.
0211        */
0212       /* Clean and invalidate the local variable cache. */
0213     #if defined(__ICCARM__)
0214     /* As we can't align the stack to the cache line size, invalidate each of the variables */
0215       SCB->DCCIMVAC = (uint32_t)&locals.sets;
0216       SCB->DCCIMVAC = (uint32_t)&locals.ways;
0217       SCB->DCCIMVAC = (uint32_t)&locals.ccsidr;
0218     #else
0219       SCB->DCCIMVAC = (uint32_t)&locals;
0220     #endif
0221       __DSB();
0222       __ISB();
0223     #endif
0224 
0225     locals.ccsidr = SCB->CCSIDR;
0226                                             /* clean & invalidate D-Cache */
0227     locals.sets = (uint32_t)(CCSIDR_SETS(locals.ccsidr));
0228     do {
0229       locals.ways = (uint32_t)(CCSIDR_WAYS(locals.ccsidr));
0230       do {
0231         SCB->DCCISW = (((locals.sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
0232                        ((locals.ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk)  );
0233         #if defined ( __CC_ARM )
0234           __schedule_barrier();
0235         #endif
0236       } while (locals.ways-- != 0U);
0237     } while(locals.sets-- != 0U);
0238 
0239     __DSB();
0240     __ISB();
0241   #endif
0242 }
0243 
0244 
0245 /**
0246   \brief   Invalidate D-Cache
0247   \details Invalidates D-Cache
0248   */
0249 __STATIC_FORCEINLINE void SCB_InvalidateDCache (void)
0250 {
0251   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
0252     uint32_t ccsidr;
0253     uint32_t sets;
0254     uint32_t ways;
0255 
0256     SCB->CSSELR = 0U;                       /* select Level 1 data cache */
0257     __DSB();
0258 
0259     ccsidr = SCB->CCSIDR;
0260 
0261                                             /* invalidate D-Cache */
0262     sets = (uint32_t)(CCSIDR_SETS(ccsidr));
0263     do {
0264       ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
0265       do {
0266         SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
0267                       ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk)  );
0268         #if defined ( __CC_ARM )
0269           __schedule_barrier();
0270         #endif
0271       } while (ways-- != 0U);
0272     } while(sets-- != 0U);
0273 
0274     __DSB();
0275     __ISB();
0276   #endif
0277 }
0278 
0279 
0280 /**
0281   \brief   Clean D-Cache
0282   \details Cleans D-Cache
0283   */
0284 __STATIC_FORCEINLINE void SCB_CleanDCache (void)
0285 {
0286   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
0287     uint32_t ccsidr;
0288     uint32_t sets;
0289     uint32_t ways;
0290 
0291     SCB->CSSELR = 0U;                       /* select Level 1 data cache */
0292     __DSB();
0293 
0294     ccsidr = SCB->CCSIDR;
0295 
0296                                             /* clean D-Cache */
0297     sets = (uint32_t)(CCSIDR_SETS(ccsidr));
0298     do {
0299       ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
0300       do {
0301         SCB->DCCSW = (((sets << SCB_DCCSW_SET_Pos) & SCB_DCCSW_SET_Msk) |
0302                       ((ways << SCB_DCCSW_WAY_Pos) & SCB_DCCSW_WAY_Msk)  );
0303         #if defined ( __CC_ARM )
0304           __schedule_barrier();
0305         #endif
0306       } while (ways-- != 0U);
0307     } while(sets-- != 0U);
0308 
0309     __DSB();
0310     __ISB();
0311   #endif
0312 }
0313 
0314 
0315 /**
0316   \brief   Clean & Invalidate D-Cache
0317   \details Cleans and Invalidates D-Cache
0318   */
0319 __STATIC_FORCEINLINE void SCB_CleanInvalidateDCache (void)
0320 {
0321   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
0322     uint32_t ccsidr;
0323     uint32_t sets;
0324     uint32_t ways;
0325 
0326     SCB->CSSELR = 0U;                       /* select Level 1 data cache */
0327     __DSB();
0328 
0329     ccsidr = SCB->CCSIDR;
0330 
0331                                             /* clean & invalidate D-Cache */
0332     sets = (uint32_t)(CCSIDR_SETS(ccsidr));
0333     do {
0334       ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
0335       do {
0336         SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
0337                        ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk)  );
0338         #if defined ( __CC_ARM )
0339           __schedule_barrier();
0340         #endif
0341       } while (ways-- != 0U);
0342     } while(sets-- != 0U);
0343 
0344     __DSB();
0345     __ISB();
0346   #endif
0347 }
0348 
0349 
0350 /**
0351   \brief   D-Cache Invalidate by address
0352   \details Invalidates D-Cache for the given address.
0353            D-Cache is invalidated starting from a 32 byte aligned address in 32 byte granularity.
0354            D-Cache memory blocks which are part of given address + given size are invalidated.
0355   \param[in]   addr    address
0356   \param[in]   dsize   size of memory block (in number of bytes)
0357 */
0358 __STATIC_FORCEINLINE void SCB_InvalidateDCache_by_Addr (volatile void *addr, int32_t dsize)
0359 {
0360   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
0361     if ( dsize > 0 ) {
0362        int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
0363       uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
0364 
0365       __DSB();
0366 
0367       do {
0368         SCB->DCIMVAC = op_addr;             /* register accepts only 32byte aligned values, only bits 31..5 are valid */
0369         op_addr += __SCB_DCACHE_LINE_SIZE;
0370         op_size -= __SCB_DCACHE_LINE_SIZE;
0371       } while ( op_size > 0 );
0372 
0373       __DSB();
0374       __ISB();
0375     }
0376   #endif
0377 }
0378 
0379 
0380 /**
0381   \brief   D-Cache Clean by address
0382   \details Cleans D-Cache for the given address
0383            D-Cache is cleaned starting from a 32 byte aligned address in 32 byte granularity.
0384            D-Cache memory blocks which are part of given address + given size are cleaned.
0385   \param[in]   addr    address
0386   \param[in]   dsize   size of memory block (in number of bytes)
0387 */
0388 __STATIC_FORCEINLINE void SCB_CleanDCache_by_Addr (volatile void *addr, int32_t dsize)
0389 {
0390   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
0391     if ( dsize > 0 ) {
0392        int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
0393       uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
0394 
0395       __DSB();
0396 
0397       do {
0398         SCB->DCCMVAC = op_addr;             /* register accepts only 32byte aligned values, only bits 31..5 are valid */
0399         op_addr += __SCB_DCACHE_LINE_SIZE;
0400         op_size -= __SCB_DCACHE_LINE_SIZE;
0401       } while ( op_size > 0 );
0402 
0403       __DSB();
0404       __ISB();
0405     }
0406   #endif
0407 }
0408 
0409 
0410 /**
0411   \brief   D-Cache Clean and Invalidate by address
0412   \details Cleans and invalidates D_Cache for the given address
0413            D-Cache is cleaned and invalidated starting from a 32 byte aligned address in 32 byte granularity.
0414            D-Cache memory blocks which are part of given address + given size are cleaned and invalidated.
0415   \param[in]   addr    address (aligned to 32-byte boundary)
0416   \param[in]   dsize   size of memory block (in number of bytes)
0417 */
0418 __STATIC_FORCEINLINE void SCB_CleanInvalidateDCache_by_Addr (volatile void *addr, int32_t dsize)
0419 {
0420   #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
0421     if ( dsize > 0 ) {
0422        int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
0423       uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
0424 
0425       __DSB();
0426 
0427       do {
0428         SCB->DCCIMVAC = op_addr;            /* register accepts only 32byte aligned values, only bits 31..5 are valid */
0429         op_addr +=          __SCB_DCACHE_LINE_SIZE;
0430         op_size -=          __SCB_DCACHE_LINE_SIZE;
0431       } while ( op_size > 0 );
0432 
0433       __DSB();
0434       __ISB();
0435     }
0436   #endif
0437 }
0438 
0439 /*@} end of CMSIS_Core_CacheFunctions */
0440 
0441 #endif /* ARM_CACHEL1_ARMV7_H */