ZYNQ的缓存系统基于ARM Cortex-A9处理器,包含L1缓存(指令缓存和数据缓存)和L2缓存。缓存一致性是一个重要问题,特别是在使用DMA或其他主机(如PL)直接访问内存时,因为数据可能存在于缓存中而尚未写回内存,或者内存中的数据可能比缓存中的新。
缓存一致性操作主要涉及以下情况:
- 当PS的CPU写数据到缓存,然后希望DMA(或其他主机)从内存读取该数据时,必须确保缓存中的数据已经写回到内存。
- 当DMA(或其他主机)将数据写入内存,然后PS的CPU希望读取该数据时,必须确保缓存中不会读取到旧数据,而是从内存中获取新数据。
ZYNQ提供了几种机制来维护缓存一致性:
- 硬件一致性:通过ACP(Accelerator Coherency Port)接口,PL可以作为一致性代理,与CPU缓存保持一致。但注意,ACP只能用于PL作为主设备访问内存,并且只能用于访问可缓存的内存区域。
- 软件管理的一致性:对于通过其他端口(如HP端口)的访问,需要软件来管理缓存一致性。主要使用以下函数:
- Xil_DCacheFlush:将数据缓存中的脏数据写回到内存,并使其在缓存中失效。
- Xil_DCacheInvalidate:使数据缓存中的特定地址范围失效,这样下次读取时将从内存中获取新数据。
具体操作:
a) 当CPU准备将数据发送给DMA(或其他通过非ACP端口的主机)时:
- 在DMA读取数据之前,确保CPU写入的数据已经从缓存写回到内存。使用Xil_DCacheFlush或Xil_DCacheFlushRange。
b) 当DMA(或其他通过非ACP端口的主机)将数据写入内存后,CPU要读取该数据:
- 在CPU读取数据之前,使缓存中该地址范围的数据失效,以便从内存中读取新的数据。使用Xil_DCacheInvalidate或Xil_DCacheInvalidateRange。
注意:对于使用ACP端口的主机,由于硬件维护一致性,通常不需要这些操作。
此外,还可以使用非缓存的内存区域来避免缓存一致性问题。例如,将用于DMA传输的内存区域设置为非缓存,这样所有对该区域的访问都会直接访问内存,而不经过缓存。但是,这可能会降低性能。
在ZYNQ中,可以通过设置MMU的页表来将内存区域设置为非缓存。或者,在定义内存段时使用特定的属性(如OCM内存,或者通过设置MPU属性)。
下面是一个例子,展示如何在DMA传输中维护缓存一致性:
假设我们有一个缓冲区,用于从PS通过DMA发送到PL(通过HP端口):
- 初始化缓冲区,并填充数据(由CPU写入)。
- 在启动DMA传输之前,刷新缓存,确保数据已经写入内存: Xil_DCacheFlushRange((u32)buffer,
length); - 启动DMA传输(PL从内存中读取数据)。
然后,当DMA将数据从PL写入内存后,PS要读取这些数据:
- 等待DMA传输完成。
- 在PS读取数据之前,使缓存失效,以确保从内存中读取最新数据:
Xil_DCacheInvalidateRange((u32)buffer, length); - 现在PS可以读取缓冲区中的数据。
对于使用ACP的情况,则不需要上述步骤,因为硬件会自动维护一致性。
另外,注意在使缓存失效或刷新时,地址必须是32字节对齐的(因为缓存行的大小是32字节),并且长度最好是32字节的倍数。如果不是,函数内部会处理,但可能会稍微影响性能。
最后,注意在裸机程序或操作系统中正确配置MMU/MPU,以确保内存区域的缓存属性正确设置。
在Linux等操作系统中,通常由DMA引擎和驱动程序处理缓存一致性,例如使用dma_alloc_coherent分配具有一致性的内存,或者使用dma_map_single等函数进行映射。但在裸机程序中,需要开发者手动管理。
总结:在ZYNQ中,对于非ACP端口的DMA传输,必须通过软件刷新和失效缓存来维护一致性。而对于ACP端口,则无需这些操作。
4875

被折叠的 条评论
为什么被折叠?



