546 lines
20 KiB
C
546 lines
20 KiB
C
/*
|
|
* cache_ap.c
|
|
*
|
|
* Created on: Jul 10, 2020
|
|
*
|
|
*/
|
|
#include <assert.h>
|
|
#include "chip.h"
|
|
#include "nmsis_core.h"
|
|
#include "cache.h"
|
|
|
|
/**
|
|
* @brief Enables the CPU instruction cache.
|
|
*
|
|
* This function activates the internal instruction cache of the CPU
|
|
* to enhance the execution speed of programs. It is part of the Hardware
|
|
* Abstraction Layer (HAL), providing an interface to manage hardware-specific
|
|
* features such as caching operations. Enabling the instruction cache allows
|
|
* for faster access to frequently executed instructions, which is crucial
|
|
* for performance-critical applications.
|
|
*/
|
|
void HAL_EnableICache(void){
|
|
#if HAL_ICACHE_VALID
|
|
__disable_irq();
|
|
EnableICache();
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Disables the CPU instruction cache.
|
|
*
|
|
* This function deactivates the internal instruction cache of the CPU
|
|
* to potentially aid in debugging or to meet specific system requirements
|
|
* where caching of instructions needs to be prevented. It is part of the Hardware
|
|
* Abstraction Layer (HAL), providing an interface to manage hardware-specific
|
|
* features such as caching operations. Disabling the instruction cache may be
|
|
* necessary in scenarios where precise control over instruction execution is required.
|
|
*/
|
|
void HAL_DisableICache(void){
|
|
#if HAL_ICACHE_VALID
|
|
__disable_irq();
|
|
DisableICache();
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Invalidates the CPU instruction cache.
|
|
*
|
|
* This function clears the contents of the internal instruction cache of the CPU.
|
|
* Invalidating the cache is useful to ensure that no stale or corrupted data is used
|
|
* by the CPU, which is particularly important after direct memory access (DMA) operations
|
|
* or after loading new programs into memory. It is part of the Hardware Abstraction Layer (HAL),
|
|
* providing an interface to manage hardware-specific features such as caching operations.
|
|
* This operation helps in maintaining data coherency and consistency across the system.
|
|
*/
|
|
void HAL_InvalidateICache(void){
|
|
#if HAL_ICACHE_VALID
|
|
__disable_irq();
|
|
MInvalICache();
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Invalidates a range of the CPU data cache based on address and size.
|
|
*
|
|
* This function clears a specific portion of the CPU's internal data cache. By providing
|
|
* an address and the size of the area, this function ensures that any modifications in
|
|
* memory in this specified range do not use stale or outdated cache entries. This is particularly
|
|
* useful for systems where memory regions are dynamically altered or when devices not supporting
|
|
* cache coherency modify the memory. It helps in maintaining data integrity and coherency
|
|
* especially in systems involving direct memory access (DMA) operations.
|
|
*
|
|
* @param addr Pointer to the start address of the memory region to invalidate.
|
|
* @param dsize Size of the memory region to invalidate, in bytes.
|
|
*/
|
|
void HAL_InvalidateICache_by_Addr(uint32_t *addr, uint32_t dsize){
|
|
#if HAL_ICACHE_VALID
|
|
__disable_irq();
|
|
unsigned long cnt = 0;
|
|
cnt = ((uint32_t)addr % HAL_ICACHE_CFG_LINE_SIZE + dsize + (HAL_ICACHE_CFG_LINE_SIZE - 1)) / HAL_ICACHE_CFG_LINE_SIZE;
|
|
MInvalICacheLines((unsigned long)addr, (unsigned long)cnt);
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Locks a range of the CPU instruction cache based on address and size.
|
|
*
|
|
* This function prevents the CPU instruction cache from being updated or invalidated within a specified
|
|
* range. It ensures that the cache entries in this range remain fixed and are not replaced or
|
|
* evicted. This can be useful in scenarios where instruction stability is critical and should not be
|
|
* changed by other operations or processes.
|
|
*
|
|
* @param addr Pointer to the start address of the memory region to lock.
|
|
* @param dsize Size of the memory region to lock, in bytes.
|
|
*/
|
|
void HAL_LockICache_by_Addr(uint32_t *addr, uint32_t dsize){
|
|
#if HAL_ICACHE_VALID
|
|
__disable_irq();
|
|
unsigned long cnt = 0;
|
|
cnt = ((uint32_t)addr % HAL_ICACHE_CFG_LINE_SIZE + dsize + (HAL_ICACHE_CFG_LINE_SIZE - 1)) / HAL_ICACHE_CFG_LINE_SIZE;
|
|
MLockICacheLines((unsigned long)addr, (unsigned long)cnt);
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Unlocks a previously locked range of the CPU instruction cache based on address and size.
|
|
*
|
|
* This function allows the CPU instruction cache to be updated or invalidated within a previously locked
|
|
* range. It ensures that the cache entries in this range can now be replaced or evicted as needed,
|
|
* returning the cache operation to its normal behavior. This is useful when the critical operation
|
|
* requiring instruction stability is complete and normal cache operations need to resume.
|
|
*
|
|
* @param addr Pointer to the start address of the memory region to unlock.
|
|
* @param dsize Size of the memory region to unlock, in bytes.
|
|
*/
|
|
void HAL_UnLockICache_by_Addr(uint32_t *addr, uint32_t dsize){
|
|
#if HAL_ICACHE_VALID
|
|
__disable_irq();
|
|
unsigned long cnt = 0;
|
|
cnt = ((uint32_t)addr % HAL_ICACHE_CFG_LINE_SIZE + dsize + (HAL_ICACHE_CFG_LINE_SIZE - 1)) / HAL_ICACHE_CFG_LINE_SIZE;
|
|
MUnlockICacheLines((unsigned long)addr, (unsigned long)cnt);
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Enables the CPU data cache.
|
|
*
|
|
* This function activates the internal data cache of the CPU
|
|
* to enhance the execution speed and efficiency of data access and processing.
|
|
* It is part of the Hardware Abstraction Layer (HAL), providing an interface to manage
|
|
* hardware-specific features such as caching operations. Enabling the data cache helps
|
|
* improve system performance by reducing memory access times and minimizing CPU idle time
|
|
* during data fetches from main memory.
|
|
*/
|
|
void HAL_EnableDCache(void){
|
|
#if HAL_DCACHE_VALID
|
|
__disable_irq();
|
|
EnableDCache();
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Disables the CPU data cache.
|
|
*
|
|
* This function deactivates the internal data cache of the CPU.
|
|
* Disabling the data cache can be useful in scenarios where data caching may lead
|
|
* to consistency issues, such as during non-cache-coherent DMA operations or when
|
|
* the predictability of every data access is required. It is part of the Hardware
|
|
* Abstraction Layer (HAL), providing an interface to manage hardware-specific features.
|
|
* Disabling the data cache ensures that all data reads and writes are directly made to
|
|
* and from the main memory, which can be crucial for real-time and safety-critical applications.
|
|
*/
|
|
void HAL_DisableDCache(void){
|
|
#if HAL_DCACHE_VALID
|
|
__disable_irq();
|
|
DisableDCache();
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Invalidates the CPU data cache.
|
|
*
|
|
* This function clears the contents of the internal data cache of the CPU.
|
|
* Invalidating the cache is essential to prevent the use of stale or incorrect data
|
|
* that might remain after changes in memory. It is commonly used after direct memory
|
|
* access (DMA) operations or when hardware devices modify memory outside of the CPU's control.
|
|
* It is part of the Hardware Abstraction Layer (HAL), providing an interface to manage
|
|
* hardware-specific features such as caching operations. This operation ensures data coherency
|
|
* and consistency across the system, particularly in systems where memory is shared between the CPU
|
|
* and other hardware components.
|
|
*/
|
|
void HAL_InvalidateDCache(void){
|
|
#if HAL_DCACHE_VALID
|
|
__disable_irq();
|
|
MInvalDCache();
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Flushes the CPU data cache.
|
|
*
|
|
* This function ensures that all modified data within the CPU's internal data cache
|
|
* are written back to the main memory. Flushing the data cache is crucial before
|
|
* any operations that require up-to-date data from other processors or hardware
|
|
* that do not have cache coherency mechanisms. It is part of the Hardware
|
|
* Abstraction Layer (HAL), providing an interface to manage hardware-specific features
|
|
* such as caching operations. This operation helps maintain data coherency and
|
|
* consistency across different parts of the system, particularly in multi-core
|
|
* or multi-processor environments.
|
|
*/
|
|
void HAL_FlushDCache(void){
|
|
#if HAL_DCACHE_VALID
|
|
__disable_irq();
|
|
MFlushDCache();
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Flushes and invalidates the CPU data cache.
|
|
*
|
|
* This function ensures that all modified data within the CPU's internal data cache
|
|
* are written back to the main memory, and then invalidates the cache to remove all entries.
|
|
* This is particularly useful in scenarios where data coherence and consistency are critical,
|
|
* such as before DMA operations where peripheral devices need to access the latest data,
|
|
* or after updating firmware that changes the memory layout. It is part of the Hardware
|
|
* Abstraction Layer (HAL), providing an interface to manage hardware-specific features
|
|
* such as caching operations. Flushing and invalidating the data cache ensures that
|
|
* no stale data is used and all future data reads are done directly from the main memory.
|
|
*/
|
|
void HAL_FlushInvalidateDCache(void){
|
|
#if HAL_DCACHE_VALID
|
|
__disable_irq();
|
|
MFlushInvalDCache();
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Invalidates a range of the CPU data cache based on address and size.
|
|
*
|
|
* This function clears a specific portion of the CPU's internal data cache. By providing
|
|
* an address and the size of the area, this function ensures that any modifications in
|
|
* memory in this specified range do not use stale or outdated cache entries. This is particularly
|
|
* useful for systems where memory regions are dynamically altered or when devices not supporting
|
|
* cache coherency modify the memory. It helps in maintaining data integrity and coherency
|
|
* especially in systems involving direct memory access (DMA) operations.
|
|
*
|
|
* @param addr Pointer to the start address of the memory region to invalidate.
|
|
* @param dsize Size of the memory region to invalidate, in bytes.
|
|
*/
|
|
void HAL_InvalidateDCache_by_Addr(uint32_t *addr, uint32_t dsize){
|
|
#if HAL_DCACHE_VALID
|
|
__disable_irq();
|
|
unsigned long cnt = 0;
|
|
cnt = ((uint32_t)addr % HAL_DCACHE_CFG_LINE_SIZE + dsize + (HAL_DCACHE_CFG_LINE_SIZE - 1)) / HAL_DCACHE_CFG_LINE_SIZE;
|
|
MInvalDCacheLines((unsigned long)addr, (unsigned long)cnt);
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Flushes a range of the CPU data cache based on address and size.
|
|
*
|
|
* This function writes back all modified data within a specified range of the CPU's internal data cache
|
|
* to the main memory. This operation is crucial for ensuring data coherence in systems where other processors
|
|
* or hardware devices access the same memory region but do not share a cache coherency mechanism. It is typically
|
|
* used prior to DMA operations or when processors in a multi-processor system access shared data.
|
|
*
|
|
* @param addr Pointer to the start address of the memory region to flush.
|
|
* @param dsize Size of the memory region to flush, in bytes.
|
|
*/
|
|
void HAL_FlushDCache_by_Addr(uint32_t *addr, uint32_t dsize){
|
|
#if HAL_DCACHE_VALID
|
|
__disable_irq();
|
|
unsigned long cnt = 0;
|
|
cnt = ((uint32_t)addr % HAL_DCACHE_CFG_LINE_SIZE + dsize + (HAL_DCACHE_CFG_LINE_SIZE - 1)) / HAL_DCACHE_CFG_LINE_SIZE;
|
|
MFlushDCacheLines((unsigned long)addr, (unsigned long)cnt);
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Flushes and invalidates a range of the CPU data cache based on address and size.
|
|
*
|
|
* This function combines the actions of writing back all modified data within a specified range
|
|
* of the CPU's internal data cache to the main memory and then invalidating the cache entries.
|
|
* This ensures that no stale data remains and all future accesses to this memory range will be
|
|
* fetched directly from the main memory. This operation is particularly vital in systems with
|
|
* non-cache-coherent DMA operations or in multi-core systems where processors need to share
|
|
* up-to-date data without any inconsistencies.
|
|
*
|
|
* @param addr Pointer to the start address of the memory region to flush and invalidate.
|
|
* @param dsize Size of the memory region to flush and invalidate, in bytes.
|
|
*/
|
|
void HAL_FlushInvalidateDCache_by_Addr(uint32_t *addr, uint32_t dsize){
|
|
#if HAL_DCACHE_VALID
|
|
__disable_irq();
|
|
unsigned long cnt = 0;
|
|
cnt = ((uint32_t)addr % HAL_DCACHE_CFG_LINE_SIZE + dsize + (HAL_DCACHE_CFG_LINE_SIZE - 1)) / HAL_DCACHE_CFG_LINE_SIZE;
|
|
MFlushInvalDCacheLines((unsigned long)addr, (unsigned long)cnt);
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Locks a range of the CPU data cache based on address and size.
|
|
*
|
|
* This function prevents the CPU data cache from being updated or invalidated within a specified
|
|
* range. It ensures that the cache entries in this range remain fixed and are not replaced or
|
|
* evicted. This can be useful in scenarios where data stability is critical and should not be
|
|
* changed by other operations or processes.
|
|
*
|
|
* @param addr Pointer to the start address of the memory region to lock.
|
|
* @param dsize Size of the memory region to lock, in bytes.
|
|
*/
|
|
void HAL_LockDCache_by_Addr(uint32_t *addr, uint32_t dsize){
|
|
#if HAL_DCACHE_VALID
|
|
__disable_irq();
|
|
unsigned long cnt = 0;
|
|
cnt = ((uint32_t)addr % HAL_DCACHE_CFG_LINE_SIZE + dsize + (HAL_DCACHE_CFG_LINE_SIZE - 1)) / HAL_DCACHE_CFG_LINE_SIZE;
|
|
MLockDCacheLines((unsigned long)addr, (unsigned long)cnt);
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Unlocks a previously locked range of the CPU data cache based on address and size.
|
|
*
|
|
* This function allows the CPU data cache to be updated or invalidated within a previously locked
|
|
* range. It ensures that the cache entries in this range can now be replaced or evicted as needed,
|
|
* returning the cache operation to its normal behavior. This is useful when the critical operation
|
|
* requiring data stability is complete and normal cache operations need to resume.
|
|
*
|
|
* @param addr Pointer to the start address of the memory region to unlock.
|
|
* @param dsize Size of the memory region to unlock, in bytes.
|
|
*/
|
|
void HAL_UnLockDCache_by_Addr(uint32_t *addr, uint32_t dsize){
|
|
#if HAL_DCACHE_VALID
|
|
__disable_irq();
|
|
unsigned long cnt = 0;
|
|
cnt = ((uint32_t)addr % HAL_DCACHE_CFG_LINE_SIZE + dsize + (HAL_DCACHE_CFG_LINE_SIZE - 1)) / HAL_DCACHE_CFG_LINE_SIZE;
|
|
MUnlockDCacheLines((unsigned long)addr, (unsigned long)cnt);
|
|
|
|
|
|
__enable_irq();
|
|
#endif
|
|
}
|
|
|
|
// This function will be abandon
|
|
int range_is_cacheable(unsigned long start, unsigned long size){
|
|
return 0;
|
|
}
|
|
|
|
void unaligned_cache_line_move(unsigned char* src, unsigned char* dst, unsigned long len)
|
|
{
|
|
|
|
__disable_irq();
|
|
int i;
|
|
unsigned char* src_p = (unsigned char*) src;
|
|
unsigned char* dst_p = (unsigned char*) dst;
|
|
for (i = 0; i < len; ++i) {
|
|
*(dst_p + i) = *(src_p + i);
|
|
}
|
|
__enable_irq();
|
|
|
|
}
|
|
void dcache_clean_range(unsigned long start, unsigned long end){
|
|
uint32_t line_mask = HAL_DCACHE_CFG_LINE_SIZE - 1;
|
|
|
|
// 对start向上取整到cache line边界
|
|
unsigned long aligned_start = (start + line_mask) & (~line_mask);
|
|
|
|
// 对end向下取整到cache line边界
|
|
unsigned long aligned_end = end & (~line_mask);
|
|
|
|
__disable_irq();
|
|
// 只有当有完整的cache line需要处理时才进行操作
|
|
if (aligned_start < aligned_end) {
|
|
HAL_FlushDCache_by_Addr((uint32_t *)aligned_start, (aligned_end - aligned_start));
|
|
}
|
|
|
|
// 对不对齐的部分进行单独处理
|
|
if (start < aligned_start) {
|
|
// 处理start到aligned_start之间的数据
|
|
// 这里需要更细粒度的处理方式
|
|
}
|
|
|
|
if (end > aligned_end) {
|
|
// 处理aligned_end到end之间的数据
|
|
// 这里需要更细粒度的处理方式
|
|
}
|
|
__enable_irq();
|
|
}
|
|
|
|
void dcache_invalidate_range(unsigned long start, unsigned long end){
|
|
uint32_t line_mask = HAL_DCACHE_CFG_LINE_SIZE - 1;
|
|
|
|
// 对start向上取整到cache line边界
|
|
unsigned long aligned_start = (start + line_mask) & (~line_mask);
|
|
|
|
// 对end向下取整到cache line边界
|
|
unsigned long aligned_end = end & (~line_mask);
|
|
|
|
__disable_irq();
|
|
|
|
// 只有当有完整的cache line需要处理时才进行操作
|
|
if (aligned_start < aligned_end) {
|
|
HAL_InvalidateDCache_by_Addr((uint32_t *)aligned_start, (aligned_end - aligned_start));
|
|
}
|
|
|
|
// 对不对齐的部分进行单独处理
|
|
if (start < aligned_start) {
|
|
// 处理start到aligned_start之间的数据
|
|
// 这里需要更细粒度的处理方式
|
|
}
|
|
|
|
if (end > aligned_end) {
|
|
// 处理aligned_end到end之间的数据
|
|
// 这里需要更细粒度的处理方式
|
|
}
|
|
__enable_irq();
|
|
}
|
|
|
|
void dcache_flush_range(unsigned long start, unsigned long end){
|
|
uint32_t line_mask = HAL_DCACHE_CFG_LINE_SIZE - 1;
|
|
|
|
// 对start向上取整到cache line边界
|
|
unsigned long aligned_start = (start + line_mask) & (~line_mask);
|
|
|
|
// 对end向下取整到cache line边界
|
|
unsigned long aligned_end = end & (~line_mask);
|
|
|
|
__disable_irq();
|
|
// 只有当有完整的cache line需要处理时才进行操作
|
|
if (aligned_start < aligned_end) {
|
|
HAL_FlushDCache_by_Addr((uint32_t *)aligned_start, (aligned_end - aligned_start));
|
|
HAL_InvalidateDCache_by_Addr((uint32_t *)aligned_start, (aligned_end - aligned_start));
|
|
}
|
|
|
|
// 对不对齐的部分进行单独处理
|
|
if (start < aligned_start) {
|
|
// 处理start到aligned_start之间的数据
|
|
// 这里需要更细粒度的处理方式
|
|
}
|
|
|
|
if (end > aligned_end) {
|
|
// 处理aligned_end到end之间的数据
|
|
// 这里需要更细粒度的处理方式
|
|
}
|
|
__enable_irq();
|
|
}
|
|
void cache_dma_fast_inv_stage1(unsigned long start, unsigned long end){
|
|
unsigned long line_size;
|
|
unsigned long old_start = start;
|
|
unsigned long old_end = end;
|
|
line_size = HAL_DCACHE_CFG_LINE_SIZE;
|
|
start = start & (~(line_size - 1));
|
|
end = (end + line_size - 1) & (~(line_size - 1));
|
|
if (start == end)
|
|
return;
|
|
|
|
__disable_irq();
|
|
if (start != old_start) {
|
|
HAL_FlushDCache_by_Addr((uint32_t *)start, line_size);
|
|
}
|
|
if (end != old_end) {
|
|
HAL_FlushDCache_by_Addr((uint32_t *)(end - line_size), line_size);
|
|
}
|
|
HAL_InvalidateDCache_by_Addr((uint32_t *)start, (end - start));
|
|
__enable_irq();
|
|
}
|
|
// void cache_dma_fast_inv_stage2(unsigned long start, unsigned long end){
|
|
|
|
// }
|
|
// dcache_clean_range(buff_addr, buff_addr + blk_sz * blk_cnt);
|
|
// gm_cpu_clean_dcache_range(q->payload, q->len);
|
|
// gm_cpu_dcache_invalidate_range(q->payload, q->len);
|
|
// cache_dma_fast_inv_stage1(buff_addr, buff_addr + blk_sz * blk_cnt);
|
|
|
|
// dcache_clean_range(buff_addr, buff_addr + blk_sz * blk_cnt);
|
|
// // usually called after transferring data to memory (NOT cache-line-aligned) via DMA
|
|
|
|
void cache_dma_fast_inv_stage2(unsigned long start, unsigned long end)
|
|
{
|
|
unsigned long line_size;
|
|
unsigned long old_start = start;
|
|
unsigned long old_end = end;
|
|
static unsigned char cache_line_buf[32];
|
|
|
|
line_size = HAL_DCACHE_CFG_LINE_SIZE;
|
|
start = start & (~(line_size - 1));
|
|
end = (end + line_size - 1) & (~(line_size - 1));
|
|
if (start == end)
|
|
return;
|
|
|
|
int use_lock = 0;
|
|
// interrupt enabled, and not in interrupt context
|
|
|
|
if(start != old_start || end != old_end)
|
|
use_lock = 1;
|
|
|
|
if (use_lock) {
|
|
disable_GINT();
|
|
}
|
|
|
|
__disable_irq();
|
|
if (start != old_start) {
|
|
unaligned_cache_line_move((unsigned char*) start, cache_line_buf, old_start - start);
|
|
HAL_InvalidateDCache_by_Addr((uint32_t *)start, line_size);
|
|
unaligned_cache_line_move(cache_line_buf, (unsigned char*) start, old_start - start);
|
|
}
|
|
if (end != old_end) {
|
|
unaligned_cache_line_move((unsigned char*) old_end, cache_line_buf, end - old_end);
|
|
HAL_InvalidateDCache_by_Addr((uint32_t *)(end - line_size), line_size);
|
|
unaligned_cache_line_move(cache_line_buf, (unsigned char*) old_end, end - old_end);
|
|
}
|
|
__enable_irq();
|
|
|
|
if (use_lock) {
|
|
enable_GINT();
|
|
}
|
|
|
|
}
|