1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
一、Cortex-M7的Cache功能
对于Cortex-M系列家族(M0+/M3/M4/M7/M23/M33/M35P/M55)来说,L1 Cache仅在Cortex-M7和Cortex-M55内核上存在,说白了,L1 Cache是专为高性能内核配置的,而目前的i.MXRT1xxx系列微控制器都是基于Cortex-M7内核。 下面是i.MXRT1050的内核系统框图,可以看到它集成了32KB D-Cache,Cache经由AXI64总线连到SIM_M7和SIM_EMS模块,最终转成AHB总线连接到FlexSPI模块,因此对于Flash的AHB读访问是可以受到D-Cache加速的。 关于D-Cache工作机制,可以在 ARM Cortex-M7 Processor Technical Reference Manual 手册中找到详细解释。简单地概括就是32KB D-Cache会被划分成1024个Cache Line,每个Cache Line大小为32个字节,四个Cache Line是一组(即所谓的4-way set associative),每一组Cache Line会有一个地址标签,地址标签用来记录Cache所缓存的数据所在目标地址信息。 L1 D-Cache使能时,对目标存储器的AHB读访问总共有两大类:Hit(要访问的数据在Cache里面)、Miss(要访问的数据不在Cache里面),Hit没什么好说的,直接从Cache里取数据就行了;Miss后则会先把数据从目标存储器中读到Cache里,然后再从Cache读出数据(这就是所谓的Read-Allocate,实际上有另一个名词Read-Through与之对应,Read-Through即直接从目标存储器中读出数据,一般是Cache不使能时的行为)。 对目标地址空间的Cache策略控制主要是属性配置(在内核MPU模块里)和开关控制(在内核SCB模块里),下面 BOARD_ConfigMPU() 函数即是典型的对FlexSPI地址映射空间所分配的Flash区域的Cache属性配置,这个代码里将0x60000000开始的64MB空间属性配成了Normal Memory,不共享,Cache使能并且写访问行为是Write-Back(写访问还有另一种策略Write-Through),读访问行为不用配置(固定Read-Allocate)。 /* MPU configuration. */void BOARD_ConfigMPU(void){ /* Disable I cache and D cache */ SCB_DisableICache(); SCB_DisableDCache(); /* Disable MPU */ ARM_MPU_Disable(); /* Region 0 setting: Instruction access disabled, No data access permission. */ MPU->RBAR = ARM_MPU_RBAR(0, 0x00000000U); MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_NONE, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4GB); /* Region 2 setting: Memory with Device type, not shareable, non-cacheable. */ MPU->RBAR = ARM_MPU_RBAR(2, 0x60000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB); #if defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1) /* Region 3 setting: Memory with Normal type, not shareable, cacheable, outer/inner write back. */ MPU->RBAR = ARM_MPU_RBAR(3, 0x60000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_RO, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_64MB);#endif /* Enable MPU */ ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk); /* Enable I cache and D cache */ SCB_EnableDCache(); SCB_EnableICache();}最后再提一下跟本文主题不相干的Cache使能下写访问行为策略: 二、D-Cache实验准备 参考文章 《实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形(无缓存)》 里的第一小节 实验准备,本次实验需要做一样的准备工作。 三、D-Cache实验代码 参考文章 《实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形(无缓存)》 里的第二小节 实验代码,本次实验代码关于工程和链接文件方面是一样的设置,但是具体测试函数改成如下ramfunc型函数 test_cacheable_read()。关于D-Cache这次会有很多种不同测试,while(1)语句前的系统配置保持不变,while(1)里面的语句可根据实际测试情况去调整: #if (defined(__ICCARM__))#pragma optimize = none__ramfunc #endifvoid test_cacheable_read(void){ // 系统配置 /* Disable L1 I-Cache*/ SCB_DisableICache(); /* Enable L1 D-Cache*/ SCB_EnableDCache(); SCB_CleanInvalidateDCache(); // 根据测试需求,开/关FlexSPI的Prefetch特性 while (1) { // 测试用例代码,可按情况调整 } }为了便于分辨IO[1:0]上的数据去帮助分析本系列测试用例结果,我们需要拓展下特殊const数据区.ahbRdBuffer设置如下: const uint8_t ahbRdBlock1[1024] @ ".ahbRdBuffer1" = {// 正顺序0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,0x20, 0x21, 0x22, 0x23, 0x30, 0x31, 0x32, 0x33,// 倒顺序0x33, 0x32, 0x31, 0x30, 0x23, 0x22, 0x21, 0x20,0x13, 0x12, 0x11, 0x10, 0x03, 0x02, 0x01, 0x00,// 正插序0x01, 0x00, 0x03, 0x02, 0x11, 0x10, 0x13, 0x12,0x21, 0x20, 0x23, 0x22, 0x31, 0x30, 0x33, 0x32,// 倒插序0x32, 0x33, 0x30, 0x31, 0x22, 0x23, 0x20, 0x21,0x12, 0x13, 0x10, 0x11, 0x02, 0x03, 0x00, 0x01,};const uint8_t ahbRdBlock2[1024] @ ".ahbRdBuffer2" = {// 倒插序0x32, 0x33, 0x30, 0x31, 0x22, 0x23, 0x20, 0x21,0x12, 0x13, 0x10, 0x11, 0x02, 0x03, 0x00, 0x01,// 正插序0x01, 0x00, 0x03, 0x02, 0x11, 0x10, 0x13, 0x12,0x21, 0x20, 0x23, 0x22, 0x31, 0x30, 0x33, 0x32,// 倒顺序0x33, 0x32, 0x31, 0x30, 0x23, 0x22, 0x21, 0x20,0x13, 0x12, 0x11, 0x10, 0x03, 0x02, 0x01, 0x00,// 正顺序0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,0x20, 0x21, 0x22, 0x23, 0x30, 0x31, 0x32, 0x33,};// 在工程链接文件中keep{ p .ahbRdBuffer1, p .ahbRdBuffer2 };place at address mem:0x60002400 { readonly p .ahbRdBuffer1 };place at address mem:0x60002800 { readonly p .ahbRdBuffer2 };四、D-Cache实验结果 4.1 重做无缓存一文中的实验 现在让我们在开启D-Cache的情况下重新做文章 《实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形(无缓存)》 中全部实验: const uint8_t ahbRdBlock1[1024] @ ".ahbRdBuffer1" = { // 正顺序 0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, 0x20, 0x21, 0x22, 0x23, 0x30, 0x31, 0x32, 0x33, // 倒顺序 0x33, 0x32, 0x31, 0x30, 0x23, 0x22, 0x21, 0x20, 0x13, 0x12, 0x11, 0x10, 0x03, 0x02, 0x01, 0x00, // 正插序 0x01, 0x00, 0x03, 0x02, 0x11, 0x10, 0x13, 0x12, 0x21, 0x20, 0x23, 0x22, 0x31, 0x30, 0x33, 0x32, // 倒插序 0x32, 0x33, 0x30, 0x31, 0x22, 0x23, 0x20, 0x21, 0x12, 0x13, 0x10, 0x11, 0x02, 0x03, 0x00, 0x01, }; const uint8_t ahbRdBlock2[1024] @ ".ahbRdBuffer2" = { // 倒插序 0x32, 0x33, 0x30, 0x31, 0x22, 0x23, 0x20, 0x21, 0x12, 0x13, 0x10, 0x11, 0x02, 0x03, 0x00, 0x01, // 正插序 0x01, 0x00, 0x03, 0x02, 0x11, 0x10, 0x13, 0x12, 0x21, 0x20, 0x23, 0x22, 0x31, 0x30, 0x33, 0x32, // 倒顺序 0x33, 0x32, 0x31, 0x30, 0x23, 0x22, 0x21, 0x20, 0x13, 0x12, 0x11, 0x10, 0x03, 0x02, 0x01, 0x00, // 正顺序 0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, 0x20, 0x21, 0x22, 0x23, 0x30, 0x31, 0x32, 0x33,}; // 在工程链接文件中keep{ p .ahbRdBuffer1, p .ahbRdBuffer2 };place at address mem:0x60002400 { readonly p .ahbRdBuffer1 };place at address mem:0x60002800 { readonly p .ahbRdBuffer2 };4.1.1 AHB_ADDR_START 取值 [0x60002400 - 0x60002418] 当 AHB_ADDR_START 取值范围在 [0x60002400 - 0x60002418] 中时,Flash端的时序波形图都是如下同一个。因为有了D-Cache,现在我们看不到周期性的CS信号了,说明除了Flash新地址访问是必须要通过FlexSPI外设去读取Flash之外,其后的同一Flash地址的重复访问都直接发生在D-Cache里了。 另外D-Cache起始缓存地址永远是32字节对齐的地址处,并且一次缓存32byte的数据(因为D-Cache Line大小就是32byte),所以波形结果里看,起始地址都是0x60002400,一次读取32byte数据(存在一个D-Cache Line里),因此之前不开D-Cache和Prefetch下的AHB Burst Read策略导致的访问不同对齐地址的波形差异测试结果在这里就不存在了。 4.1.2 AHB_ADDR_START = 0x60002419 当实际代码中要读取的Flash数据会横跨两个相邻32字节对齐的数据块(0x60002400 - 0x6000241f, 0x60002420 - 0x6000243f),此时Flash端会出现两次CS有效信号,每次均传输32byte数据,D-Cache一直在持续作用,这次动用了两个D-Cache Line(D-Cache总大小有32KB,共有1024个Cache Line),因此在Flash端我们还是看不到周期性CS信号。 4.1.3 追加实验,从0x60002400处读取1KB 当代码循环读取1KB数据时,波形图上可以看到32个CS有效信号,每个CS有效期间传输32byte数据,总计1KB数据的传输,D-Cache这次派出了32个 Cache Line,在Flash端我们依然看不到周期性CS信号。 4.2 重做有预取一文中的实验 现在让我们在开启D-Cache的情况下重新做文章 《实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形(有预取)》 中全部实验: 4.2.1 循环读取首地址32字节对齐的1KB空间内的任意长度数据块,起始拷贝地址位于前31个字节内 这种情况下,Flash端实际波形与 《实抓Flash信号波形来看i.MXRT的FlexSPI外设下AHB读访问情形(有预取)》 中 4.1 里的测试结果差不多,这里就不再贴图了。Prefetch机制做第一层缓存,D-Cache获取Prefetch Buffer里的结果做二次缓存,唯一的差异是因为D-Cache的存在,缓存起始地址可能会发生变化(从八字节对齐变成了32字节对齐): #define PREFETCH_TEST_ALIGNMENT (7) // 可取值 0 - 31 #define PREFETCH_TEST_START (0x60002400 + PREFETCH_TEST_ALIGNMENT) uint32_t testLen = 0x1; // 可取值 1 - (1KB-PREFETCH_TEST_ALIGNMENT) void test_cacheable_read(void) { // 略去系统配置(I-Cache关闭,Prefetch开启,D-Cache开启) while (1) { memcpy((void *)0x20200000, (void *)PREFETCH_TEST_START, testLen); } } 4.2.2 循环读取大于1KB的数据块或首地址非32字节对齐的1KB数据块 这种情况下,Flash端会有两次完整的1KB Prefetch操作,第一次Prefetch操作读取了0x60002400处的1KB,第二次Prefetch操作读取了0x60002800处的1KB。因为有D-Cache的存在,第二次Prefetch操作有了足够时间去完成,不用额外插入软延时去避免其被while(1)循环回来的下一次访问需求打断了: void test_cacheable_read(void) { // 略去系统配置(I-Cache关闭,Prefetch开启,D-Cache开启) while (1) { memcpy((void *)0x20200001, (void *)0x60002401, 0x400); } } } 4.2.3 循环读取两个不同数据块(在首地址32字节对齐的两个不同1KB空间内) 这种情况下,即使有D-Cache存在,第一次CS期间的Prefetch操作(即memcpy((void *)0x20200000, (void *)0x60002400, 0x100);引发的)还是被第二次CS的Prefetch操作打断了(即memcpy((void *)0x20200400, (void *)0x60002800, 0x100);),但是第二次CS期间的Prefetch操作不会再被打断,因为接下来while(1)循环回来的Flash数据访问需求已经缓存在D-Cache里: void test_cacheable_read(void) { // 略去系统配置(I-Cache关闭,Prefetch开启,D-Cache开启) while (1) { memcpy((void *)0x20200000, (void *)0x60002400, 0x100); memcpy((void *)0x20200400, (void *)0x60002800, 0x100); } } 4.3 如何在D-Cache使能的情况下看到周期性CS信号 前面测试了那么多种情况,我们有没有可能在Flash端看到周期性CS信号呢,即Flash持续地被读取呢?当然可以,我们知道D-Cache总大小是32KB,我们只要循环拷贝32KB以上数据,D-Cache就开始hold不住了,这不,下面代码就能让我们看到久违的周期时序波形图了(小心,Flash持续工作会多耗电的,哈哈)。 void test_cacheable_read(void) { // 略去系统配置(I-Cache关闭,Prefetch开启,D-Cache开启) while (1) { memcpy((void *)0x20200000, (void *)0x60002400, 0x8000 + 1); } } 1); } } |
|
|
|
只有小组成员才能发言,加入小组>>
3323 浏览 9 评论
3000 浏览 16 评论
3498 浏览 1 评论
9073 浏览 16 评论
4093 浏览 18 评论
1194浏览 3评论
614浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
603浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2343浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1902浏览 2评论
小黑屋| 手机版| Archiver| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-30 20:00 , Processed in 1.038913 second(s), Total 49, Slave 40 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号