言简意赅的介绍M7内核的Cache工作流程,摸爬滚打半年的经验总结--转至安富莱
[复制链接]
本帖最后由 宋元浩 于 2020-8-10 20:33 编辑
说明:
初学M7的Cache时,经常是ARM的手册和ST的手册看了一遍又一遍,虽然每次看,每次都有收获,但是一直无法形成系统的认识,说到某一个知识点也明白,但是具体到读写操作的时候是怎么个流程,就懵逼了,也是心里烦躁,最近脑子开窍了些,特此分享下经验。
当前的认识能力有限,有不对的地方,欢迎批评指正。
一、引出问题:
当前芯片厂商出的M7内核芯片基本都做了一级Cache支持,Cache又分数据缓存D-Cache和指令缓冲I-Cache,对于指令缓冲,用户不用管,这里主要说的是数据缓存D-Cache。以STM32H7为例,主频是400MHz,除了TCM和Cache以400MHz工作,其它AXI SRAM,SRAM1,SRAM2等都是以200MHz工作。数据缓存D-Cache就是解决CPU加速访问SRAM。
如果每次CPU要读写SRAM区的数据,都能够在Cache里面进行,自然是最好的,实现了200MHz到400MHz的飞跃,实际是做不到的,因为数据Cache只有16KB大小,总有用完的时候。
对于使能了Cache的SRAM区,要分读写两种情况考虑。
读操作:
如果CPU要读取的SRAM区数据在Cache中已经加载好,这就叫读命中(Cache hit),如果Cache里面没有怎么办,这就是所谓的读Cache Miss。
写操作:
如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域(专业词汇叫Cache Line,以32字节为单位),这就叫写命中(Cache hit),如果Cache里面没有开辟对应的区域怎么办,这就是所谓的写Cache Miss。
二、支持的Cache配置:
Cache的配置是通过MPU来设置的,通常只用到下几种方式。
其中的TEX是用来设置Cache策略的,C是Cache,B是缓冲用来配合Cache设置的,而S是共享,用来解决多总线或者多核访问时的同步问题。MPU配置的时候,最主要的也是配置这几个参数。
Cache支持的策略有如下四种:
有了这四种方式,就可以在正式进入本帖的主题,Cache的读写操作是如何工作的,下面分这四种情况做一 一介绍。
三、四种Cache(MPU)配置的读写操作流程说明
1、 Non-cacheable
这个最好理解,就是正常的读写操作,无Cache。
(1)对应四种MPU配置如下:
TEX = 000 C=0 B=0 S=忽略此位,强制为共享
TEX = 000 C=0 B=1 S=忽略此位,强制为共享
TEX = 001 C=0 B=0 S=0
TEX = 001 C=0 B=0 S=1
2、Write through, read allocate,no write allocate
注意,M7内核只要开启了Cache,read allocate就是开启的。
(1)使能了此配置的SRAM缓冲区写操作
如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会同时写到Cache里面和SRAM里面;如果没有,就用到配置no write allocate了,意思就是CPU会直接往SRAM里面写数据,而不再需要在Cache里面开辟空间了。
在写Cache命中的情况下,这个方式的优点是Cache和SRAM的数据同步更新了,没有多总线访问造成的数据一致性问题。缺点也明显,Cache在写操作上无法有效发挥性能。
(2)使能了此配置的SRAM缓冲区读操作
如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。
安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。
(3)对应两种MPU配置如下:
TEX = 000 C=1 B=0 S=1
TEX = 000 C=1 B=0 S=0
3、Write back, read allocate,no write allocate
注意,M7内核只要开启了Cache,read allocate就是开启的。
(1)使能了此配置的SRAM缓冲区写操作
如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会写到Cache里面,而不会立即更新SRAM;如果没有,就用到配置no write allocate了,意思就是CPU会直接往SRAM里面写数据,而不再需要在Cache里面开辟空间了。
安全隐患,如果Cache命中的情况下,此时仅Cache更新了,而SRAM没有更新,那么DMA直接从SRAM里面读出来的就是错误的。
(2)使能了此配置的SRAM缓冲区读操作
如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。
安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。
(3)对应两种MPU配置如下:
TEX = 000 C=1 B=1 S=1
TEX = 000 C=1 B=1 S=0
4、Write back, read allocate,write allocate
注意,M7内核只要开启了Cache,read allocate就是开启的。
(1)使能了此配置的SRAM缓冲区写操作
如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会写到Cache里面,而不会立即更新SRAM;如果没有,就用到配置write allocate了,意思就是CPU写到往SRAM里面的数据,会同步在Cache里面开辟一个空间将SRAM中写入的数据加载进来,如果此时立即读此SRAM区,那么就会有很大的速度优势。
安全隐患,如果Cache命中的情况下,此时仅Cache更新了,而SRAM没有更新,那么DMA直接从SRAM里面读出来的就是错误的。
(2)使能了此配置的SRAM缓冲区读操作
如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。
安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。
这个配置被誉可以最大程度发挥Cache性能,不过具体应用仍需具体分析。
(3)对应两种MPU配置如下:
TEX = 001 C=1 B=1 S=1
TEX = 001 C=1 B=1 S=0
5、共享配置是个隐形的大坑
这里以STM32H7为例进行说明,STM32H7编程手册对其的描述是多核共享。
而H7的应用笔记对齐的描述是开启共享基本等同于关闭Cache。
实际测试下面四种开Cache的情况,开关共享对缓冲区的大批量数据的读操作影响很大,基本差出两倍,而写操作基本没有影响,也许这就是所谓的多总线同步读造成的。
另外共享开关仅对开启了Cache的情况下有影响,而对于关闭了Cache的情况是没有影响的,开不开没关系。
6、总结这几种方式的几个关键知识点
(1)Cortex-M7内核的L1 Cache由多行内存区组成,每行有32字节,每行都配有一个地址标签。数据缓冲DCache是每4行为一组,称为4-way set associative。而指令缓冲区ICache是2行为一组,这样节省地址标签,不用每个行都标记一个地址。
(2)对于读操作,只有在第1次访问指定地址时才会加载到Cache,而写操作的话,可以直接写到内存中(write-through模式)或者放到Cache里面,后面再写入(write-back模式)。
(3)如果采用的是Write back,Cache line会被标为dirty,等到此行被evicted时,才会执行实际的写操作,将Cache Line里面的数据写入到相应的存储区。
(4)Cache命中是访问的地址落在了给定的Cache Line里面,所以硬件需要做少量的地址比较工作,以检查此地址是否被缓存。如果命中了,将用于缓存读操作或者写操作。如果没有命中,则分配和标记新行,填充新的读写操作。如果所有行都分配完毕了,Cache控制器将支持eviction操作。根据Cache Line替换算法,一行将被清除Clean,无效化Invalid或者重新配置。数据缓存和指令缓存是采用的伪随机替换算法。
(5)Cache支持的4种基本操作,使能,禁止,清空和无效化。Clean清空操作是将Cache Line中标记为dirty的数据写入到内存里面,而无效化Invalid是将Cache Line标记为无效,即删除操作。
四、面对这种繁冗复杂的Cache配置,推荐方式和安全隐患解决如下(以H7为例):
(1)推荐使用128KB的TCM作为主RAM区,其它的专门用于大缓冲和DMA操作等。
(2)Cache问题主要是CPU和DMA都操作这个缓冲区时容易出现,使用时要注意。
(3)Cache配置的选择,优先考虑的是WB,然后是WT和关闭Cache,其中WB和WT的使用中可以配合ARM提供的如下几个函数解决上面说到的隐患问题。但不是万能的,在不起作用的时候,直接暴力选择函数SCB_CleanInvlaidateDCache解决。关于这个问题,在分别配置以太网MAC的描述符缓冲区,发送缓冲区和接收缓冲区时尤其突出。
回帖1:
M7暴露了很多体系结构的知识给MCU程序员,而MCU程序员往往对现代计算机的体系结构知之甚少。。推荐阅读《计算机组成与设计:硬件软件接口》,补充一些how it works的原理性知识,对认识现在越来越复杂的MCU、MPU系统也有好处,当然,对于更硬核的开发者,比如对CPU设计感兴趣的工程师,还有编译器程序员,《计算机体系结构:量化研究方法》是上一本的进阶读物…
回帖2:
你好,请问如果设置cache属性为WT的,那么在写入得时候即写到cache又写到主存储器中,那么对写来说,性能是没有提升的,是这样么?
答:对
回帖3:
其实看完了还是一头雾水,因为没有结合HAL库代码讲解,根本不知道各个模式如何去设置
答:这四个补上就跟HAL对应上了。
B = MPU_InitStruct.IsBufferable;
C= MPU_InitStruct.IsCacheable;
S = MPU_InitStruct.IsShareable;
TEX = MPU_InitStruct.TypeExtField;
回帖4:
c,s的描述看明白了,b(缓冲)能再讲讲吗?目前看介绍是开启wb时要开启缓冲,但是他缓冲的是什么东西那?
s的意思是不是cpu在读内存的时候,Cache控制器会去看一下。其他cpu有没有写过这块内存,而没有刷cache,导致开启share比关闭会慢那么多?
答:b是配合c使用的。一般情况下关闭S就行。一些手册中对S的理解就是:开了S就相当于关闭了C,也就是关闭了Cache
回帖5:
E:代表独占(Exclusive)
S:代表共享(Shared)
无论是独占状态还是共享状态,缓存里面的数据都是“干净”的。这个“干净”,自然对应的是前面所说的“脏”的,也就是说,这个时候,Cache Block 里面的数据和主内存里面的数据是一致的。
那么“独占”和“共享”这两个状态的差别在哪里呢?这个差别就在于,在独占状态下,对应的 Cache Line 只加载到了当前 CPU 核所拥有的 Cache 里。其他的 CPU 核,并没有加载对应的数据到自己的 Cache 里。这个时候,如果要向独占的 Cache Block 写入数据,我们可以自由地写入数据,而不需要告知其他 CPU 核。
在独占状态下的数据,如果收到了一个来自于总线的读取对应缓存的请求,它就会变成共享状态。这个共享状态是因为,这个时候,另外一个 CPU 核心,也把对应的 Cache Block,从内存里面加载到了自己的 Cache 里来。
而在共享状态下,因为同样的数据在多个 CPU 核心的 Cache 里都有。所以,当我们想要更新 Cache 里面的数据的时候,不能直接修改,而是要先向所有的其他 CPU 核心广播一个请求,要求先把其他 CPU 核心里面的 Cache,都变成无效的状态,然后再更新当前 Cache 里面的数据。这个广播操作,一般叫作 RFO(Request For Ownership),也就是获取当前对应 Cache Block 数据的所有权。
在看MESI协议的时候看到了共享的解释,不过好像和H7的策略不一样,MESI协议在写时会有影响,但是读很快,而H7刚好相反
|