mirror of
https://github.com/cesanta/mongoose.git
synced 2024-12-16 02:19:18 +08:00
430 lines
13 KiB
C
430 lines
13 KiB
C
/******************************************************************************
|
|
* @file cachel1_armv7.h
|
|
* @brief CMSIS Level 1 Cache API for Armv7-M and later
|
|
* @version V1.0.1
|
|
* @date 19. April 2021
|
|
******************************************************************************/
|
|
/*
|
|
* Copyright (c) 2020-2021 Arm Limited. All rights reserved.
|
|
*
|
|
* 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 License at
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#if defined ( __ICCARM__ )
|
|
#pragma system_include /* treat file as system include file for MISRA check */
|
|
#elif defined (__clang__)
|
|
#pragma clang system_header /* treat file as system include file */
|
|
#endif
|
|
|
|
#ifndef ARM_CACHEL1_ARMV7_H
|
|
#define ARM_CACHEL1_ARMV7_H
|
|
|
|
/**
|
|
\ingroup CMSIS_Core_FunctionInterface
|
|
\defgroup CMSIS_Core_CacheFunctions Cache Functions
|
|
\brief Functions that configure Instruction and Data cache.
|
|
@{
|
|
*/
|
|
|
|
/* Cache Size ID Register Macros */
|
|
#define CCSIDR_WAYS(x) (((x) & SCB_CCSIDR_ASSOCIATIVITY_Msk) >> SCB_CCSIDR_ASSOCIATIVITY_Pos)
|
|
#define CCSIDR_SETS(x) (((x) & SCB_CCSIDR_NUMSETS_Msk ) >> SCB_CCSIDR_NUMSETS_Pos )
|
|
|
|
#ifndef __SCB_DCACHE_LINE_SIZE
|
|
#define __SCB_DCACHE_LINE_SIZE 32U /*!< Cortex-M7 cache line size is fixed to 32 bytes (8 words). See also register SCB_CCSIDR */
|
|
#endif
|
|
|
|
#ifndef __SCB_ICACHE_LINE_SIZE
|
|
#define __SCB_ICACHE_LINE_SIZE 32U /*!< Cortex-M7 cache line size is fixed to 32 bytes (8 words). See also register SCB_CCSIDR */
|
|
#endif
|
|
|
|
/**
|
|
\brief Enable I-Cache
|
|
\details Turns on I-Cache
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_EnableICache (void)
|
|
{
|
|
#if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
|
|
if (SCB->CCR & SCB_CCR_IC_Msk) return; /* return if ICache is already enabled */
|
|
|
|
__DSB();
|
|
__ISB();
|
|
SCB->ICIALLU = 0UL; /* invalidate I-Cache */
|
|
__DSB();
|
|
__ISB();
|
|
SCB->CCR |= (uint32_t)SCB_CCR_IC_Msk; /* enable I-Cache */
|
|
__DSB();
|
|
__ISB();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Disable I-Cache
|
|
\details Turns off I-Cache
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_DisableICache (void)
|
|
{
|
|
#if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
|
|
__DSB();
|
|
__ISB();
|
|
SCB->CCR &= ~(uint32_t)SCB_CCR_IC_Msk; /* disable I-Cache */
|
|
SCB->ICIALLU = 0UL; /* invalidate I-Cache */
|
|
__DSB();
|
|
__ISB();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Invalidate I-Cache
|
|
\details Invalidates I-Cache
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_InvalidateICache (void)
|
|
{
|
|
#if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
|
|
__DSB();
|
|
__ISB();
|
|
SCB->ICIALLU = 0UL;
|
|
__DSB();
|
|
__ISB();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
\brief I-Cache Invalidate by address
|
|
\details Invalidates I-Cache for the given address.
|
|
I-Cache is invalidated starting from a 32 byte aligned address in 32 byte granularity.
|
|
I-Cache memory blocks which are part of given address + given size are invalidated.
|
|
\param[in] addr address
|
|
\param[in] isize size of memory block (in number of bytes)
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_InvalidateICache_by_Addr (volatile void *addr, int32_t isize)
|
|
{
|
|
#if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
|
|
if ( isize > 0 ) {
|
|
int32_t op_size = isize + (((uint32_t)addr) & (__SCB_ICACHE_LINE_SIZE - 1U));
|
|
uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_ICACHE_LINE_SIZE - 1U) */;
|
|
|
|
__DSB();
|
|
|
|
do {
|
|
SCB->ICIMVAU = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */
|
|
op_addr += __SCB_ICACHE_LINE_SIZE;
|
|
op_size -= __SCB_ICACHE_LINE_SIZE;
|
|
} while ( op_size > 0 );
|
|
|
|
__DSB();
|
|
__ISB();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Enable D-Cache
|
|
\details Turns on D-Cache
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_EnableDCache (void)
|
|
{
|
|
#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
|
|
uint32_t ccsidr;
|
|
uint32_t sets;
|
|
uint32_t ways;
|
|
|
|
if (SCB->CCR & SCB_CCR_DC_Msk) return; /* return if DCache is already enabled */
|
|
|
|
SCB->CSSELR = 0U; /* select Level 1 data cache */
|
|
__DSB();
|
|
|
|
ccsidr = SCB->CCSIDR;
|
|
|
|
/* invalidate D-Cache */
|
|
sets = (uint32_t)(CCSIDR_SETS(ccsidr));
|
|
do {
|
|
ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
|
|
do {
|
|
SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
|
|
((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk) );
|
|
#if defined ( __CC_ARM )
|
|
__schedule_barrier();
|
|
#endif
|
|
} while (ways-- != 0U);
|
|
} while(sets-- != 0U);
|
|
__DSB();
|
|
|
|
SCB->CCR |= (uint32_t)SCB_CCR_DC_Msk; /* enable D-Cache */
|
|
|
|
__DSB();
|
|
__ISB();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Disable D-Cache
|
|
\details Turns off D-Cache
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_DisableDCache (void)
|
|
{
|
|
#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
|
|
uint32_t ccsidr;
|
|
uint32_t sets;
|
|
uint32_t ways;
|
|
|
|
SCB->CSSELR = 0U; /* select Level 1 data cache */
|
|
__DSB();
|
|
|
|
SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk; /* disable D-Cache */
|
|
__DSB();
|
|
|
|
/*
|
|
* For the endless loop issue with GCC O0.
|
|
* More details, see https://github.com/ARM-software/CMSIS_5/issues/620
|
|
*
|
|
* The issue only happens when local variables are in stack (GCC O0). If
|
|
* local variables are saved in general purpose register, then the function
|
|
* is OK.
|
|
*
|
|
* When local variables are in stack, after disabling the cache, flush the
|
|
* local variables cache line for data consistency.
|
|
*/
|
|
/* Clean and invalidate the local variable cache. */
|
|
SCB->DCCIMVAC = (uint32_t)(&sets);
|
|
SCB->DCCIMVAC = (uint32_t)(&ways);
|
|
SCB->DCCIMVAC = (uint32_t)(&ccsidr);
|
|
__DSB();
|
|
__ISB();
|
|
|
|
ccsidr = SCB->CCSIDR;
|
|
|
|
/* clean & invalidate D-Cache */
|
|
sets = (uint32_t)(CCSIDR_SETS(ccsidr));
|
|
do {
|
|
ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
|
|
do {
|
|
SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
|
|
((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk) );
|
|
#if defined ( __CC_ARM )
|
|
__schedule_barrier();
|
|
#endif
|
|
} while (ways-- != 0U);
|
|
} while(sets-- != 0U);
|
|
|
|
__DSB();
|
|
__ISB();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Invalidate D-Cache
|
|
\details Invalidates D-Cache
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_InvalidateDCache (void)
|
|
{
|
|
#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
|
|
uint32_t ccsidr;
|
|
uint32_t sets;
|
|
uint32_t ways;
|
|
|
|
SCB->CSSELR = 0U; /* select Level 1 data cache */
|
|
__DSB();
|
|
|
|
ccsidr = SCB->CCSIDR;
|
|
|
|
/* invalidate D-Cache */
|
|
sets = (uint32_t)(CCSIDR_SETS(ccsidr));
|
|
do {
|
|
ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
|
|
do {
|
|
SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
|
|
((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk) );
|
|
#if defined ( __CC_ARM )
|
|
__schedule_barrier();
|
|
#endif
|
|
} while (ways-- != 0U);
|
|
} while(sets-- != 0U);
|
|
|
|
__DSB();
|
|
__ISB();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Clean D-Cache
|
|
\details Cleans D-Cache
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_CleanDCache (void)
|
|
{
|
|
#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
|
|
uint32_t ccsidr;
|
|
uint32_t sets;
|
|
uint32_t ways;
|
|
|
|
SCB->CSSELR = 0U; /* select Level 1 data cache */
|
|
__DSB();
|
|
|
|
ccsidr = SCB->CCSIDR;
|
|
|
|
/* clean D-Cache */
|
|
sets = (uint32_t)(CCSIDR_SETS(ccsidr));
|
|
do {
|
|
ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
|
|
do {
|
|
SCB->DCCSW = (((sets << SCB_DCCSW_SET_Pos) & SCB_DCCSW_SET_Msk) |
|
|
((ways << SCB_DCCSW_WAY_Pos) & SCB_DCCSW_WAY_Msk) );
|
|
#if defined ( __CC_ARM )
|
|
__schedule_barrier();
|
|
#endif
|
|
} while (ways-- != 0U);
|
|
} while(sets-- != 0U);
|
|
|
|
__DSB();
|
|
__ISB();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
\brief Clean & Invalidate D-Cache
|
|
\details Cleans and Invalidates D-Cache
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_CleanInvalidateDCache (void)
|
|
{
|
|
#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
|
|
uint32_t ccsidr;
|
|
uint32_t sets;
|
|
uint32_t ways;
|
|
|
|
SCB->CSSELR = 0U; /* select Level 1 data cache */
|
|
__DSB();
|
|
|
|
ccsidr = SCB->CCSIDR;
|
|
|
|
/* clean & invalidate D-Cache */
|
|
sets = (uint32_t)(CCSIDR_SETS(ccsidr));
|
|
do {
|
|
ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
|
|
do {
|
|
SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
|
|
((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk) );
|
|
#if defined ( __CC_ARM )
|
|
__schedule_barrier();
|
|
#endif
|
|
} while (ways-- != 0U);
|
|
} while(sets-- != 0U);
|
|
|
|
__DSB();
|
|
__ISB();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
\brief D-Cache Invalidate by address
|
|
\details Invalidates D-Cache for the given address.
|
|
D-Cache is invalidated starting from a 32 byte aligned address in 32 byte granularity.
|
|
D-Cache memory blocks which are part of given address + given size are invalidated.
|
|
\param[in] addr address
|
|
\param[in] dsize size of memory block (in number of bytes)
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_InvalidateDCache_by_Addr (volatile void *addr, int32_t dsize)
|
|
{
|
|
#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
|
|
if ( dsize > 0 ) {
|
|
int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
|
|
uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
|
|
|
|
__DSB();
|
|
|
|
do {
|
|
SCB->DCIMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */
|
|
op_addr += __SCB_DCACHE_LINE_SIZE;
|
|
op_size -= __SCB_DCACHE_LINE_SIZE;
|
|
} while ( op_size > 0 );
|
|
|
|
__DSB();
|
|
__ISB();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
\brief D-Cache Clean by address
|
|
\details Cleans D-Cache for the given address
|
|
D-Cache is cleaned starting from a 32 byte aligned address in 32 byte granularity.
|
|
D-Cache memory blocks which are part of given address + given size are cleaned.
|
|
\param[in] addr address
|
|
\param[in] dsize size of memory block (in number of bytes)
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_CleanDCache_by_Addr (volatile void *addr, int32_t dsize)
|
|
{
|
|
#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
|
|
if ( dsize > 0 ) {
|
|
int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
|
|
uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
|
|
|
|
__DSB();
|
|
|
|
do {
|
|
SCB->DCCMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */
|
|
op_addr += __SCB_DCACHE_LINE_SIZE;
|
|
op_size -= __SCB_DCACHE_LINE_SIZE;
|
|
} while ( op_size > 0 );
|
|
|
|
__DSB();
|
|
__ISB();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
\brief D-Cache Clean and Invalidate by address
|
|
\details Cleans and invalidates D_Cache for the given address
|
|
D-Cache is cleaned and invalidated starting from a 32 byte aligned address in 32 byte granularity.
|
|
D-Cache memory blocks which are part of given address + given size are cleaned and invalidated.
|
|
\param[in] addr address (aligned to 32-byte boundary)
|
|
\param[in] dsize size of memory block (in number of bytes)
|
|
*/
|
|
__STATIC_FORCEINLINE void SCB_CleanInvalidateDCache_by_Addr (volatile void *addr, int32_t dsize)
|
|
{
|
|
#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
|
|
if ( dsize > 0 ) {
|
|
int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U));
|
|
uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */;
|
|
|
|
__DSB();
|
|
|
|
do {
|
|
SCB->DCCIMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */
|
|
op_addr += __SCB_DCACHE_LINE_SIZE;
|
|
op_size -= __SCB_DCACHE_LINE_SIZE;
|
|
} while ( op_size > 0 );
|
|
|
|
__DSB();
|
|
__ISB();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*@} end of CMSIS_Core_CacheFunctions */
|
|
|
|
#endif /* ARM_CACHEL1_ARMV7_H */
|