From 48727ca537c15ac9feb46d98eb5f6c0ad3687a65 Mon Sep 17 00:00:00 2001 From: David Crocker Date: Tue, 1 Dec 2020 17:26:11 +0000 Subject: [PATCH] Merged SAME5x and SAM4E cache management code --- cores/arduino/Cache.cpp | 137 +++++++++++++++++++++++----------------- cores/arduino/Cache.h | 10 +-- 2 files changed, 84 insertions(+), 63 deletions(-) diff --git a/cores/arduino/Cache.cpp b/cores/arduino/Cache.cpp index 325cf0de..26fdf6f5 100644 --- a/cores/arduino/Cache.cpp +++ b/cores/arduino/Cache.cpp @@ -7,7 +7,7 @@ #include "Cache.h" -#if !SAMC21 && !SAM4S && !SAM3XA +#if SAM4E || SAME70 || SAME5x #if SAME70 # include @@ -17,6 +17,8 @@ extern uint32_t _nocache_ram_start; extern uint32_t _nocache_ram_end; +static bool cacheEnabled = false; + # if USE_MPU # include @@ -43,40 +45,61 @@ extern uint32_t _nocache_ram_end; # endif -#endif +#else -#if SAM4E -# include +// SAM4E and SAME5x use fairly similar cache controllers + +inline bool is_cache_enabled() noexcept +{ +#if SAME5x + return CMCC->SR.bit.CSTS; +#elif SAM4E + return (CMCC->CMCC_SR & CMCC_SR_CSTS) != 0; #endif +} +inline void cache_invalidate_all() noexcept +{ #if SAME5x + CMCC->MAINT0.reg = CMCC_MAINT0_INVALL; +#elif SAM4E + CMCC->CMCC_MAINT0 = CMCC_MAINT0_INVALL; +#endif + __ISB(); + __DSB(); +} -inline void cache_disable() +inline void cache_disable() noexcept { - while (CMCC->SR.bit.CSTS) + while (is_cache_enabled()) { +#if SAME5x CMCC->CTRL.reg = 0; +#elif SAM4E + CMCC->CMCC_CTRL = 0; +#endif __ISB(); __DSB(); } } -inline void cache_enable() -{ - CMCC->CTRL.reg = CMCC_CTRL_CEN; - __ISB(); - __DSB(); -} - -inline void cache_invalidate_all() +inline void cache_enable() noexcept { - CMCC->MAINT0.reg = CMCC_MAINT0_INVALL; + if (!is_cache_enabled()) + { + cache_invalidate_all(); +#if SAME5x + CMCC->CTRL.reg = CMCC_CTRL_CEN; +#elif SAM4E + CMCC->CMCC_CTRL = CMCC_CTRL_CEN; +#endif + __ISB(); + __DSB(); + } } #endif -static bool enabled = false; - void Cache::Init() noexcept { #if SAME70 @@ -169,55 +192,51 @@ void Cache::Init() noexcept # endif #elif SAME5x - // No need to do any initialisation + CMCC->MCFG.reg = CMCC_MCFG_MODE_DHIT_COUNT; // data hit mode + CMCC->MEN.bit.MENABLE = 1; #elif SAM4E - CMCC->CMCC_MCFG = CMCC_DHIT_COUNT_MODE; + CMCC->CMCC_MCFG = 2; // data hit mode CMCC->CMCC_MEN |= CMCC_MEN_MENABLE; #endif } void Cache::Enable() noexcept { - if (!enabled) - { - enabled = true; #if SAME70 + if (!cacheEnabled) + { + cacheEnabled = true; SCB_EnableICache(); SCB_EnableDCache(); -#elif SAME5x - cache_invalidate_all(); - cache_enable(); -#elif SAM4E - CMCC->CMCC_MAINT0 = CMCC_MAINT0_INVALL; // invalidate all lines - CMCC->CMCC_CTRL = CMCC_CTRL_CEN; // enable cache -#endif } +#else + cache_enable(); +#endif } // Disable the cache, returning true if it was enabled bool Cache::Disable() noexcept { - if (enabled) - { #if SAME70 + const bool wasEnabled = cacheEnabled; + if (wasEnabled) + { SCB_DisableICache(); SCB_DisableDCache(); // this cleans it as well as disabling it -#elif SAME5x - cache_disable(); -#elif SAM4E - CMCC->CMCC_CTRL = 0; // disable cache -#endif - enabled = false; - return true; + cacheEnabled = false; } - return false; +#else + const bool wasEnabled = is_cache_enabled(); + cache_disable(); +#endif + return wasEnabled; } #if SAME70 void Cache::Flush(const volatile void *start, size_t length) noexcept { - if (enabled) + if (cacheEnabled) { // We assume that the DMA buffer is entirely inside or entirely outside the non-cached RAM area if (start < (void*)&_nocache_ram_start || start >= (void*)&_nocache_ram_end) @@ -232,9 +251,9 @@ void Cache::Flush(const volatile void *start, size_t length) noexcept void Cache::Invalidate(const volatile void *start, size_t length) noexcept { - if (enabled) - { #if SAME70 + if (cacheEnabled) + { // We assume that the DMA buffer is entirely inside or entirely outside the non-cached RAM area if (start < (void*)&_nocache_ram_start || start >= (void*)&_nocache_ram_end) { @@ -242,37 +261,39 @@ void Cache::Invalidate(const volatile void *start, size_t length) noexcept const uint32_t startAddr = reinterpret_cast(start); SCB_InvalidateDCache_by_Addr(reinterpret_cast(startAddr & ~3), length + (startAddr & 3)); } -#elif SAME5x - //TODO can we invalidate just the relevant cache line(s)? - // Disable interrupts throughout the sequence, otherwise we could get a task switch while the cache is disabled. - // The can cause a crash because we end up invalidating the cache while it is enabled. + } +#else + // We just invalidate the whole cache + if (is_cache_enabled()) + { + // Disable interrupts to prevent a task switch, otherwise we may end up with the cache disabled in another task const irqflags_t flags = cpu_irq_save(); cache_disable(); cache_invalidate_all(); cache_enable(); cpu_irq_restore(flags); -#elif SAM4E - // The cache is only 2kb on the SAM4E so we just invalidate the whole cache - const irqflags_t flags = cpu_irq_save(); - CMCC->CMCC_CTRL = 0; // disable cache - __ISB(); - CMCC->CMCC_MAINT0 = CMCC_MAINT0_INVALL; // invalidate all lines - CMCC->CMCC_CTRL = CMCC_CTRL_CEN; // enable cache - cpu_irq_restore(flags); -#endif } + else + { + cache_invalidate_all(); + } +#endif } -#if SAM4E +#if SAM4E || SAME5x uint32_t Cache::GetHitCount() noexcept { - return cmcc_get_monitor_cnt(CMCC); +#if SAM4E + return CMCC->CMCC_MSR; +#elif SAME5x + return CMCC->MSR.reg; +#endif } #endif -#endif // !SAMC21 && !SAM4S && !SAM3XA +#endif // SAM4E || SAME70 || SAME5x // Entry points that can be called from ASF C code void CacheFlushBeforeDMAReceive(const volatile void *start, size_t length) noexcept { Cache::FlushBeforeDMAReceive(start, length); } diff --git a/cores/arduino/Cache.h b/cores/arduino/Cache.h index 47b883a4..f591b366 100644 --- a/cores/arduino/Cache.h +++ b/cores/arduino/Cache.h @@ -5,8 +5,8 @@ * Author: David */ -#ifndef SRC_HARDWARE_CACHE_H_ -#define SRC_HARDWARE_CACHE_H_ +#ifndef SRC_CACHE_H_ +#define SRC_CACHE_H_ #include @@ -22,7 +22,7 @@ namespace Cache inline void InvalidateAfterDMAReceive(const volatile void *start, size_t length) noexcept { Invalidate(start, length); } inline void FlushBeforeDMASend(const volatile void *start, size_t length) noexcept { Flush(start, length); } -#if SAM4E +#if SAM4E || SAME5x uint32_t GetHitCount() noexcept; #endif }; @@ -43,9 +43,9 @@ inline void Cache::Invalidate(const volatile void *start, size_t length) noexcep #elif SAM4E || SAME5x -// The SAM4E cache is write-through, so no need to flush it +// The SAM4E and SAME5x cache is write-through, so no need to flush it inline void Cache::Flush(const volatile void *start, size_t length) noexcept { __DSB(); } #endif -#endif /* SRC_HARDWARE_CACHE_H_ */ +#endif /* SRC_CACHE_H_ */