一,cache概述

从下图可以看出,从M7内核才开始有的cache,这对于从M0,M3,M4一路走来的小伙伴来说,多了一个cache就多了一个障碍。

Cortex-M7 core with 32K/32K L1 I/D-Cache!这提供了极高的性能,代码无论是从芯片上的内存,外部闪存,还是外部内存运行!介绍种类包括:L1 cache, memory types, attributes and MPU(Memory Protection Unit). 指导用户如何使用缓存开发以正确和高性能方式运行应用程序。

cache价值:由于对这些存储器的子系统,比如 OCRAM,FlexSPI,SEMC的访问可能需要多个周期(特别是在具有多个等待状态的外部存储器接口上),因此L1缓存的设计目的是加快对存储器的读/写操作。这带来了很大的性能提升。

I/DTCM(FlexRAM banks configured as TCM)由CPU核直接访问,绕过L1缓存。因此,建议将关键代码和数据放入TCM中,就像向量表vector table一样

flush:在有的书中称作invalidate

存贮器结构如下图:

Cortex-M7是6级双发射流水线,下图是一个示意图。

高速缓存cache基础知识:

程序执行的局部规律性包括时间局部规律性和空间局部规律性。

时间局部规律性:在程序执行过程中,刚刚被访问的信息可能很快被再次访问,典型情况是程序中存在大量的循环。

空间局部规律性:在程序执行过程中,那些与被访问的地址相临近的信息也有可能很快被访问。典型情况是程序中存在大量的顺序执行。

按照程序执行的“局部性规律”,程序中的数据或者代码被访问后,该数据和代码以及邻近的数据代码近期再被访问的概率要远大于,近期未被访问的数据或者代码被访问的概率。因此,当数据或代码被访问后,被认为是经常访问的数据和代码,将被存入到cache,当再次访问该数据或者代码时直接从该cache读取数据或者代码的值,而不是到内存中重新读取。

有了cache后,core对内存中的数据访问流程如下图所示:

二.Cortex-M7内核的L1 Cache

L1 Cache由多行内存区组成,每行有32字节,每行都配有一个地址标签。

数据缓冲DCache:是每4行为一组,称为4-way set associative。

指令缓冲区ICache:是2行为一组, 称为2-way set-associative

这样节省地址标签,不用每个行都标记一个地址。

Cache hit:要访问的数据/指令在cache里面.

Cache miss:要访问的数据/指令不在cache里面.

Core 读cache时:

若hit,则直接从cache读出数据即可。

若miss,有两种处理方式:

>read through ,直接从内存中读出

>read allocate,先把数据读到cache,再从cache读出。如果 CPU 要读取的 SRAM 区数据在 Cache 中已经加载好,就可以直接从 Cache 里面读取。如果没有,就用到配置 read allocate 了,意思就是在 Cache 里面开辟区域,将 SRAM 区数据加载进来,后续的操作,CPU 可以直接从 Cache 里面读取,从而时间加速。

Core 写cache时:

若hit,两种处理方式:

>write-through模式:

可以直接写到内存中同时放到Cache里面,优点是内存和cache同步更新,没有多总线访问造成的数据一致性问题,缺点是无法在写操作上面发挥性能。

>Write back模式:Cache line会被标为dirty,等到此行被evicted(驱逐,赶出, flush)时,才会执行实际的写操作,将Cache Line里面的数据写入到相应的存 储区。Write back安全隐患:如果 Cache 命中的情况下,此时仅 Cache 更新了,而 SRAM,SDRAM 没有更新,那么 DMA 直接从 SRAM 里面读出来的就是错误的。

若miss,两种处理方式:

>write-allocate:先把要写的数据载入到cache,写cache,然后再flush进内存。

>no-write-allocate:直接写入内存。

Cache 命中是访问的地址落在了给定的 Cache Line 里面,所以硬件需要做少量的地址比较工作,以检查此地址是否被缓存。如果命中了,将用于缓存读操作或者写操作。如果没有命中,则分配和标记新行,填充新的读写操作。如果所有行都分配完毕了,Cache 控制器将支持 eviction 操作。根据 Cache Line 替换算法,一行将被清除 Clean,无效化 Invalid 或者重新配置。数据缓存和指令缓存是采用的伪随机替换算法。Cache支持的4种基本操作,1.使能,2.禁止,3.清空,4.无效化。

Clean清空操作是将Cache Line中标记为dirty的数据写入到内存里面,无效化Invalid是将 Cache Line 标记为无效,等同于删除操作。这样Cache 空间就都腾出来了,可以加载新的指令/数据。

三.cache配合MPU使用

MPU(memory protection unit),首先需要通过MPU配置相应memory的属性(normal, strongly-ordered, device, XN etc.)

RT1052存储器默认映射和属性

四.什么是 cache 一致性问题

对于指令缓冲I-Cache,用户不用管,这里主要说的是数据缓存 D-Cache。

所谓的 Cache 一致性问题, 主要指的是由于 D-cache 存在时,表现在有多个 Host(典型的如 MCU 的 Core, DMA 等)访问同一块内存时, 由于数据会缓存在 D-cache 中而没有更新实际的物理内存。

在实际应用中,有以下两种情况:

4.1

第一种情况是当有core写物理内存(SRAM,0x20200000)的指令时,(对应SDK例程:*(uint8_t *)(startAddr + count) = 0xffu;)Core 会先去更新相应的 cache-line(Write-back 策略),在没有 clean 的情况下,会导致其对应的实际物理内存中的数据并没有被更新,如果这个时候有其它的 Host(如 DMA)访问这段内存时,就会出现问题(由于实际物理内存并未被更新,和 D-cache 中的不一致),如果clean一下(对应SDK例程:L1CACHE_CleanDCacheByRange(startAddr, MEM_DMATRANSFER_LEN);)这就是所谓的 cache 一致性的问题。

4.2

第二种情况是 DMA 更新了某段物理内存(DMA 和 cache 直接没有直接通道),而这个时候 Core 再读取这段内存的时候,由于相对应地址的 cache-line 没有被 invalidate,导致 Core 读到的是 cache-line 中的数据,而非被 DMA 更新过的实际物理内存的数据。

五。解决 cache 一致性问题

有两种可选方案:

一.所有的共享存储器都定义为共享属性

  • 这些区域将默认不被缓存到 D-Cache。

  • 所有的操作都直接针对二级存储器(内部Flash,外部存储器),性能降低。

  • 因为缓存对这些区域是透明的,写软件更容易

二.通过软件进行cache的维护

(1)Cortex-M7 的写操作要是全局可见的

    • 使用透写属性(通过 MPU 设置)。

    • 使用 SIWT@CACR(Shared = Write Through)。

    • 通过指令清 D-cache,然后所有更新位置禁止 D-Cache操作

这种情况,在DMA从SRAM搬运数据到SDRAM时,需要先执行clean。

L1CACHE_CleanInvalidateDCache();

(2)其他主设备的写操作要对 Cortex-M7 可见

    • 比如作废 Cortex-M7 Dache 中数据

这种情况,在DMA从SDRAM搬运数据到SRAM时,需要搬运后执行Invalidate。

    L1CACHE_CleanInvalidateDCache()

六.常见函数解释

SCB_EnableICache() 和 SCB_EnableDCache()

  使能 I-cache 或 D-cache。

SCB_DisableICache() 和 SCB_DisableDCache()

  禁用 I-cache 或 D-cache。

SCB_InvalidateICache()

  使 I-cache 无效,I-cache 被 invalidate 之后,当读取指令时,会忽略相应的 cache-line 中的内容(因为被 validate 了),而从真实的物理地址中去获取相应的指令

SCB_InvalidateDCache()

  使 D-cache 无效,D-cache 被 invalidate 之后,当有 Host(如 core,DMA 等)读取数据时,会忽略相应的 cache-line 中的内容( 因为被 validate 了),从真实的物理地址中去获取相应的数据

SCB_InvalidateDCache_by_Addr()

  根据地址信息无效其对应的 cache-line。

SCB_CleanDCache()

  Clean 所有的 cache-line,即将 dirty 的 cache-line 全部写到 cache line 对应的真实的物理地址中所谓的 drity 属性,

即写操作时, 更新了相应的 cache-line,但是没有更新到真实的物理地址,而这个 clean 的动作, 就是将 cache 中的内容更新到真实的物理地址中。

SCB_CleanDCache_by_Addr()

  根据地址信息 clean 其对应的 cache-line

SCB_CleanInvalidateDCache_by_Addr()

  根据地址信息 clean 并 invalidate 其对应的 cache-line。

SCB_CleanInvalidateDCache()

七. 其他指令解释

功能描述
DMB
数据存储器隔离。DMB 指令保证: 仅当所有在它前面的存储器访问操作
都执行完毕后,才提交(commit)在它后面的存储器访问操作。

DSB
数据同步隔离。比 DMB 严格: 仅当所有在它前面的存储器访问操作
都执行完毕后,才执行在它后面的指令(亦即任何指令都要等待存储器访 问操作——译者注)

ISB
指令同步隔离。最严格:它会清洗流水线,以保证所有它前面的指令都执
行完毕之后,才执行它后面的指令。

对于高级底层技巧:“自我更新”(self-mofifying)代码,非常有用。举例 来说,如果某个程序从下一条要执行的指令处更新了自己,

但是先前的旧指令已经被预取到流水线 中去了,此时就必须清洗流水线,把旧版本的指令洗出去,再预取新版本的指令。因此,必须在被 更新代码段的前面使用 ISB,以保证旧的代码从流水线中被清洗出去,不再有机会执行

Bootloader在跳转到app之前的清洗,就是1个例子,如下:

--------------------------------------------

  LPUART_Deinit(LPUART1);

    vSceneRenew();

__ISB();

    __DSB();

    /* Enable I cache and D cache */

    SCB_DisableDCache();

    SCB_DisableICache();

vControlSwitch();

--------------------------------------------------------------------

L1CACHE_InvalidateICacheByRange函数也是1个例子:

/**Invalidate cortex-m7 L1 instruction cache by range.***/

void L1CACHE_InvalidateICacheByRange(uint32_t address, uint32_t size_byte)

{

#if (__DCACHE_PRESENT == 1U)

 uint32_t addr = address & (uint32_t)~(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE - 1);

    int32_t size = size_byte + address - addr;

    uint32_t linesize = 32U;

 __DSB();

 while (size > 0)

    {

        SCB->ICIMVAU = addr;

        addr += linesize;

        size -= linesize;

  }

    __DSB();

    __ISB();

#endif    

}

以上内容参考了网上很多博客,还有官方文档,再次表示感谢,若有侵权,请联系删除,谢谢!

技术交流微信 18124528727.

-------------------------------------------------END---------------------------------------------------------------

Cortex_m7内核cache深入了解和应用的更多相关文章

  1. linux 内核cache

    写驱动总会碰到和cache相关的东西 记录下用到的接口: 驱动中用的内存地址一般为内核地址,用户调用驱动接口时,有时候会把自己申请的地址赋给驱动,此时用户kmalloc得到内核地址, 再用mmap获得 ...

  2. Linux内核中内存cache的实现【转】

    Linux内核中内存cache的实现 转自:http://blog.chinaunix.net/uid-127037-id-2919545.html   本文档的Copyleft归yfydz所有,使用 ...

  3. 协程 & 用户级(内核级)线程 & 切换开销 & 协程与异步回调的差异

    今天先是看到多线程级别的内容,然后又看到协程的内容. 基本的领会是,协程是对异步回调方式的一种变换,同样是在一个线程内,协程通过主动放弃时间片交由其他协程执行来协作,故名协程. 而协程很早就有了,那时 ...

  4. 【内核】linux内核启动流程详细分析

    Linux内核启动流程 arch/arm/kernel/head-armv.S 该文件是内核最先执行的一个文件,包括内核入口ENTRY(stext)到start_kernel间的初始化代码, 主要作用 ...

  5. 【内核】linux内核启动流程详细分析【转】

    转自:http://www.cnblogs.com/lcw/p/3337937.html Linux内核启动流程 arch/arm/kernel/head-armv.S 该文件是内核最先执行的一个文件 ...

  6. 77%的Linux运维都不懂的内核问题

    前言 之前在实习时,听了 OOM 的分享之后,就对 Linux 内核内存管理充满兴趣,但是这块知识非常庞大,没有一定积累,不敢写下,担心误人子弟,所以经过一个一段时间的积累,对内核内存有一定了解之后, ...

  7. linux下epoll实现机制

    linux下epoll实现机制 原作者:陶辉 链接:http://blog.csdn.net/russell_tao/article/details/7160071 先简单回顾下如何使用C库封装的se ...

  8. linux I/O复用

    转载自:哈维.dpkirin url:http://blog.csdn.NET/zhang_shuai_2011/article/details/7675797 http://blog.csdn.Ne ...

  9. Android的进程等级

    Android五个进程等级 1.前台进程(Foreground process): 用户当前工作所需要的.一个进程如果满足下列任何条件被认为是前台进程: 正运行着一个正在与用户交互的活动(Activi ...

随机推荐

  1. NGINX实现咏南跨平台中间件集群

    NGINX实现咏南跨平台中间件集群 首先要开启咏南LINUX中间件. 1)编辑usr/local/nginx/conf/nginx.conf #user  nobody;worker_processe ...

  2. Unity3D地下守护神ARPG开发三部曲 视频教程+素材+源码

    通过大型教学项目“MMOARPG地下守护神”项目的学习,掌握常用设计模式.架构设计.各种重要算法与设计模式在项目中的灵活运用,学后达到中高级游戏研发人员水平,做主程必备. 适用人群    学习Unit ...

  3. 使用adb 命令(atrace)抓起systrace的方法。【转】

    本文转载自:https://www.cnblogs.com/liuliu-word/p/9963017.html adb shell atrace -c -b 10240 --async_start ...

  4. 文献阅读 | Molecular Architecture of the Mouse Nervous System

    文章亮点: 按level来管理和分析数据,文章有不同stage,每个stage有不同subtype,这应该是一个真tree,而不只是一个进化树,文章里出现最多的进化树把所有的stage都整合了. 空间 ...

  5. 表观 | Enhancer | ChIP-seq | 转录因子 | 数据库专题

    需要长期更新! 参考:生信修炼手册 enhancer的基本概念: 长度几十到几千bp,作用是提高靶基因活性,属于顺式作用原件,DNA作用到DNA,转录因子就是反式,是结合到DNA的蛋白. 1981年, ...

  6. JS正则表达式使用

    <script type="text/javascript"> function SubmitCk() { var reg = /^([a-zA-Z0-9]+[_|\_ ...

  7. PHP实现执行定时任务

    首先用命令检查服务是否在运行 systemctl status crond.service 如果服务器上没有装有crontab ,则可以执行 yum install vixie-cron yum in ...

  8. Oracle数据库启动报错,找不到数据文件(ORA-01157和ORA-01110)

    数据库报了ORA-01157和ORA-01110错误,提示找不到一个数据文件. 1.启动数据库报错 在启动数据库过程中,报了ORA-01157和ORA-01110错误,提示找不到数据文件. SQL&g ...

  9. [原][osg][OSGEARTH]OE的关闭打开自动计算裁剪面被OE的海洋ocean影响

    在osgEarthUtil 下 Ocean.cpp 的  traverse函数中: // we don't want the ocean participating in the N/F calcul ...

  10. Flutter BottomNavigationBar 组件

    BottomNavigationBar 是底部导航条,可以让我们定义底部 Tab 切换,bottomNavigationBar是 Scaffold 组件的参数. BottomNavigationBar ...