本帖最后由 baiyongbin2009 于 2018-11-6 01:01 编辑 ( I/ P7 @7 ?" h # Q @1 A9 v, \# @ 说明:1 H2 {/ m: A/ i5 T+ I 初学M7的Cache时,经常是ARM的手册和ST的手册看了一遍又一遍,虽然每次看,每次都有收获,但是一直无法形成系统的认识,说到某一个知识点也明白,但是具体到读写操作的时候是怎么个流程,就懵逼了,也是心里烦躁,最近脑子开窍了些,特此分享下经验。 2 @2 L9 {1 M3 W- g U; a7 | 当前的认识能力有限,有不对的地方,欢迎批评指正。 一、引出问题: d6 O4 s% W% X" w% F0 ~ 当前芯片厂商出的M7内核芯片基本都做了一级Cache支持,Cache又分数据缓存D-Cache和指令缓冲I-Cache,对于指令缓冲,用户不用管,这里主要说的是数据缓存D-Cache。以STM32H7为例,主频是400MHz,除了TCM和Cache以400MHz工作,其它AXI SRAM,SRAM1,SRAM2等都是以200MHz工作。数据缓存D-Cache就是解决CPU加速访问SRAM。; V" @1 n9 x% A, m; e* F; z 如果每次CPU要读写SRAM区的数据,都能够在Cache里面进行,自然是最好的,实现了200MHz到400MHz的飞跃,实际是做不到的,因为数据Cache只有16KB大小,总有用完的时候。2 O" w2 G" T: E) I `' p 7 M3 y, F0 s2 R+ H7 C6 Q( i 对于使能了Cache的SRAM区,要分读写两种情况考虑。 读操作:. c4 Z! T& M$ G! J0 d. F1 D( { 如果CPU要读取的SRAM区数据在Cache中已经加载好,这就叫读命中(Cache hit),如果Cache里面没有怎么办,这就是所谓的读Cache Miss。 写操作: 如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域(专业词汇叫Cache Line,以32字节为单位),这就叫写命中(Cache hit),如果Cache里面没有开辟对应的区域怎么办,这就是所谓的写Cache Miss。 * S4 b% }# l8 e* F' h6 { ( I( o. x/ k3 K$ D( S. l & z6 k$ `2 J. |! P 二、支持的Cache配置: Cache的配置是通过MPU来设置的,通常只用到下几种方式。 % z# }! N5 W7 N& o+ S 其中的TEX是用来设置Cache策略的,C是Cache,B是缓冲用来配合Cache设置的,而S是共享,用来解决多总线或者多核访问时的同步问题。MPU配置的时候,最主要的也是配置这几个参数。( G) J; |+ y8 B. m( h1 ~ Cache支持的策略有如下四种: , J9 q9 ~2 L1 I8 ]# }% m 有了这四种方式,就可以在正式进入本帖的主题,Cache的读写操作是如何工作的,下面分这四种情况做一 一介绍。 三、四种Cache(MPU)配置的读写操作流程说明6 L3 o" G0 X; n8 o9 @+ H 1、 Non-cacheable5 p, |! ^3 w. ^. g 这个最好理解,就是正常的读写操作,无Cache。7 T: G: [% _8 F$ N' b $ U- `2 a6 k" g6 _ (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=19 |# P! p# L$ y6 o& T. k1 d , a# \$ v# @" @7 J" _: ` 2、Write through, read allocate,no write allocate 注意,M7内核只要开启了Cache,read allocate就是开启的。4 U& H8 h1 a* ]; x7 a% j # @* i; f" Y9 d& o a: N+ @ (1)使能了此配置的SRAM缓冲区写操作 如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会同时写到Cache里面和SRAM里面;如果没有,就用到配置no write allocate了,意思就是CPU会直接往SRAM里面写数据,而不再需要在Cache里面开辟空间了。0 |1 P, e6 ~, A6 T p ) `- }% c7 x! j 在写Cache命中的情况下,这个方式的优点是Cache和SRAM的数据同步更新了,没有多总线访问造成的数据一致性问题。缺点也明显,Cache在写操作上无法有效发挥性能。$ E1 d' U; g. b3 D (2)使能了此配置的SRAM缓冲区读操作+ ?# Y* g( ^7 U5 H' b 如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。4 ^) }# H; f4 B3 U ' l& o9 {/ g/ Z! n! B 安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。 4 B2 x+ ^" F" ~7 x+ a* u" P (3)对应两种MPU配置如下:/ Y1 ~# E5 B7 X$ M% a TEX = 000 C=1 B=0 S=1- ^& j' i# G9 g+ c- J) R TEX = 000 C=1 B=0 S=0% Z+ A' {" _; i4 m9 E4 Q 0 M! Z7 R8 `* q 3、Write back, read allocate,no write allocate 注意,M7内核只要开启了Cache,read allocate就是开启的。 / }) H" Z5 ^, v! M (1)使能了此配置的SRAM缓冲区写操作 如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会写到Cache里面,而不会立即更新SRAM;如果没有,就用到配置no write allocate了,意思就是CPU会直接往SRAM里面写数据,而不再需要在Cache里面开辟空间了。 5 ~4 B8 A( {1 W5 m0 Q" r 安全隐患,如果Cache命中的情况下,此时仅Cache更新了,而SRAM没有更新,那么DMA直接从SRAM里面读出来的就是错误的。 % P4 X' C$ F3 P% ]9 y" p: @ r (2)使能了此配置的SRAM缓冲区读操作 如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。 / ^$ X/ w. \7 M! a o: E, B4 \: F 安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。2 {, P3 N) @ T) E0 p% z! ]! g # \0 U- U( |" A+ s0 s1 ^! a (3)对应两种MPU配置如下: TEX = 000 C=1 B=1 S=1" W% t( y+ k2 \' p% R; [ TEX = 000 C=1 B=1 S=0 4、Write back, read allocate,write allocate0 Q9 ]7 x3 A5 `) O. F7 Q$ q 注意,M7内核只要开启了Cache,read allocate就是开启的。 ) f; D) l+ F, ~8 @7 y2 c (1)使能了此配置的SRAM缓冲区写操作6 f$ t) @0 y# H3 O 如果CPU要写的SRAM区数据在Cache中已经开辟了对应的区域,那么会写到Cache里面,而不会立即更新SRAM;如果没有,就用到配置write allocate了,意思就是CPU写到往SRAM里面的数据,会同步在Cache里面开辟一个空间将SRAM中写入的数据加载进来,如果此时立即读此SRAM区,那么就会有很大的速度优势。 安全隐患,如果Cache命中的情况下,此时仅Cache更新了,而SRAM没有更新,那么DMA直接从SRAM里面读出来的就是错误的。7 F O$ E7 s; L/ U$ J0 _( N (2)使能了此配置的SRAM缓冲区读操作1 a3 t" q" @; I: i8 P, I8 C; y! T 如果CPU要读取的SRAM区数据在Cache中已经加载好,就可以直接从Cache里面读取。如果没有,就用到配置read allocate了,意思就是在Cache里面开辟区域,将SRAM区数据加载进来,后续的操作,CPU可以直接从Cache里面读取,从而时间加速。) n1 T4 Y" @9 r 6 N8 I: M, `7 p5 P5 o: t 安全隐患,如果Cache命中的情况下,DMA写操作也更新了SRAM区的数据,CPU直接从Cache里面读取的数据就是错误的。* w7 r( @; ]0 ?2 P2 D+ { 这个配置被誉可以最大程度发挥Cache性能,不过具体应用仍需具体分析。 : s% J* b. W( d+ U: {, M, V (3)对应两种MPU配置如下:! z% f) ~7 y2 [. N4 i3 @+ @ TEX = 001 C=1 B=1 S=19 Z# t. C6 g1 h; [ TEX = 001 C=1 B=1 S=0 5 x; e3 _ D: w: h9 g5 Z% y Z 5、共享配置是个隐形的大坑 这里以STM32H7为例进行说明,STM32H7编程手册对其的描述是多核共享。 / Y! n( K( c) C & G5 X1 f3 S9 M( ^! [9 _ 而H7的应用笔记对齐的描述是开启共享基本等同于关闭Cache。% ~: Q0 p) Q) r( N . o- G) R+ q! j8 |0 Z 1 P- Y' w5 @5 _# C1 } q8 t 实际测试下面四种开Cache的情况,开关共享对缓冲区的大批量数据的读操作影响很大,基本差出两倍,而写操作基本没有影响,也许这就是所谓的多总线同步读造成的。 另外共享开关仅对开启了Cache的情况下有影响,而对于关闭了Cache的情况是没有影响的,开不开没关系。 6、总结这几种方式的几个关键知识点! V9 {; O: n: x4 a4 G, J& L, M (1)Cortex-M7内核的L1 Cache由多行内存区组成,每行有32字节,每行都配有一个地址标签。数据缓冲DCache是每4行为一组,称为4-way set associative。而指令缓冲区ICache是2行为一组,这样节省地址标签,不用每个行都标记一个地址。 (2)对于读操作,只有在第1次访问指定地址时才会加载到Cache,而写操作的话,可以直接写到内存中(write-through模式)或者放到Cache里面,后面再写入(write-back模式)。& i0 |$ H0 X5 ]% |. |' E9 A. O 9 @$ }9 G" e" {9 O' y (3)如果采用的是Write back,Cache line会被标为dirty,等到此行被evicted时,才会执行实际的写操作,将Cache Line里面的数据写入到相应的存储区。 3 `; Q5 y1 n9 j (4)Cache命中是访问的地址落在了给定的Cache Line里面,所以硬件需要做少量的地址比较工作,以检查此地址是否被缓存。如果命中了,将用于缓存读操作或者写操作。如果没有命中,则分配和标记新行,填充新的读写操作。如果所有行都分配完毕了,Cache控制器将支持eviction操作。根据Cache Line替换算法,一行将被清除Clean,无效化Invalid或者重新配置。数据缓存和指令缓存是采用的伪随机替换算法。 . A V6 N3 t# D4 J8 z (5)Cache支持的4种基本操作,使能,禁止,清空和无效化。Clean清空操作是将Cache Line中标记为dirty的数据写入到内存里面,而无效化Invalid是将Cache Line标记为无效,即删除操作。 9 G. i; C" p s1 t" _6 \! c: e 四、面对这种繁冗复杂的Cache配置,推荐方式和安全隐患解决如下(以H7为例):! n; k- j1 j( s$ l% n (1)推荐使用128KB的TCM作为主RAM区,其它的专门用于大缓冲和DMA操作等。5 H2 [1 _1 {4 H, ?0 ~0 P: W9 z (2)Cache问题主要是CPU和DMA都操作这个缓冲区时容易出现,使用时要注意。 (3)Cache配置的选择,优先考虑的是WB,然后是WT和关闭Cache,其中WB和WT的使用中可以配合ARM提供的如下几个函数解决上面说到的隐患问题。但不是万能的,在不起作用的时候,直接暴力选择函数SCB_CleanInvlaidateDCache解决。关于这个问题,在分别配置以太网MAC的描述符缓冲区,发送缓冲区和接收缓冲区时尤其突出。! q1 l F7 g! L 7 B$ J9 l6 S4 g3 R$ u: x1 L8 C" R |
2,3,4的读是一样的