缓存 (Cache)
概述
各个 CPU 的缓存行长度如下:
CPU |
Type |
Size (B) |
Way |
Cache line length (B) |
---|---|---|---|---|
KM4 |
I-Cache |
16K |
4 |
32 |
D-Cache |
16K |
4 |
32 |
|
KM0 |
I-Cache |
16K |
4 |
32 |
D-Cache |
16K |
4 |
32 |
CPU |
Type |
Size (B) |
Way |
Cache line length (B) |
---|---|---|---|---|
KM4 |
I-Cache |
16K |
4 |
32 |
D-Cache |
16K |
4 |
32 |
|
KR4 |
I-Cache |
16K |
4 |
32 |
D-Cache |
16K |
4 |
32 |
CPU |
Type |
Size (B) |
Way |
Cache line length (B) |
---|---|---|---|---|
KM4 |
I-Cache |
16K |
4 |
32 |
D-Cache |
16K |
4 |
32 |
|
KR4 |
I-Cache |
16K |
4 |
32 |
D-Cache |
16K |
4 |
32 |
|
DSP |
I-Cache |
32K |
4 |
128 |
D-Cache |
48K |
3 |
128 |
CPU |
Type |
Size (B) |
Way |
Cache line length (B) |
---|---|---|---|---|
KM4 |
I-Cache |
64K |
4 |
32 |
D-Cache |
32K |
4 |
32 |
|
KM0 |
I-Cache |
16K |
2 |
32 |
D-Cache |
8K |
2 |
32 |
|
CA32 |
L1 I-Cache |
32K |
2 |
64 |
L1 D-Cache |
32K |
4 |
64 |
|
L2 Cache |
256K |
8 |
64 |
片内缓存支持 Enable/Disable、Flush 和 Clean 操作。在 main()
函数之前,各个 CPU 均已调用 Cache_Enable()
启用了 Cache。
操作 |
描述 |
I-Cache |
D-Cache |
---|---|---|---|
Enable/Disable |
启用或禁用缓存功能 |
√ |
√ |
Flush (Invalidate) |
|
√ |
√ |
Clean |
|
x |
√ |
备注
CA32 invalidate 某个地址时,只有处于 clean 状态的缓存行才会执行清空操作,处于 dirty 状态缓存行会执行 clean & invalidate 操作。
CA32 和 DSP 具有自动数据预取功能,当 CPU 预测未来将需要访问的数据时,CPU 会在后台执行行填充操作,自动将数据加载到 Cache 中。
对于 CA32 和 DSP,
DCache_Clean()
/DCache_CleanInvalidate()
操作会将整个缓存行写入内存。当两个 CPU(具有不同的缓存行大小)使用共享内存通信时,共享内存必须与较大的缓存行对齐,以避免数据覆盖问题。例如:如果共享内存只有 32 字节,缓存行大小为 32 字节的 CPU0 每次清理时只会写入 32 字节,而缓存行大小为 64 字节的 CPU1 每次清理时会写入 64 字节,可能会覆盖 CPU0 的其他数据。
API 参考
ICache_Enable
void ICache_Enable(void)
启用 I-Cache
ICache_Disable
void ICache_Disable(void)
禁用 I-Cache
ICache_Invalidate
void ICache_Invalidate(void)
清空 I-Cache
DCache_IsEnabled
u32 DCache_IsEnabled(void)
确认 D-Cache 是否启用,返回值:
1:启用
0:禁用
DCache_Enable
void DCache_Enable(void)
启用 D-Cache
DCache_Disable
void DCache_Disable(void)
禁用 D-Cache
DCache_Invalidate
void DCache_Invalidate(u32 Address, u32 Bytes)
通过地址清空 D-Cache,参数说明:
Address
:失效地址(按缓存行长度对齐)Bytes
:内存块大小(单位:字节)
DCache_Clean
void DCache_Clean(u32 Address, u32 Bytes)
通过地址清理 D-Cache,参数说明:
Address
:清理地址(按缓存行长度对齐)Bytes
:内存块大小(单位:字节)
DCache_CleanInvalidate
void DCache_CleanInvalidate(u32 Address, u32 Bytes)
通过地址清理和清空 D-Cache,参数说明:
Address
:需清理并失效的地址(按缓存行长度对齐)Bytes
:内存块大小(单位:字节)
备注
Address 和 Bytes 同时为 0xFFFFFFFF,表示清理或者清空全部 D-Cache。
Address 和 Bytes 必须按缓存行长度对齐,如果不对齐,例如缓存行长度为 32 字节,Address 为 0x20000003C,Bytes 为 0x00000008时,那么操作的地址范围跨越了 2 个缓存行,实际操作的地址范围为 0x200000020 ~ 0x20000003F 和 0x200000040 ~ 0x20000005F,此时会导致预期外的问题。
如何定义非缓存数据缓冲区
在缓冲区定义前添加宏 SRAM_NOCACHE_DATA_SECTION,可定义具有非缓存属性 (Non-Cacheable) 的数据缓冲区。
SRAM_NOCACHE_DATA_SECTION u8 noncache_buffer[DATA_BUFFER_SIZE];
在缓冲区定义前添加宏 SRAM_NOCACHE_DATA_SECTION,可定义具有非缓存属性 (Non-Cacheable) 的数据缓冲区。
SRAM_NOCACHE_DATA_SECTION u8 noncache_buffer[DATA_BUFFER_SIZE];
备注
对于KR4:非缓存属性仅能通过 MCCA寄存器 配置,因此无法直接通过宏定义实现非缓存缓冲区。
在缓冲区定义前添加宏 SRAM_NOCACHE_DATA_SECTION,可定义具有非缓存属性 (Non-Cacheable) 的数据缓冲区。
SRAM_NOCACHE_DATA_SECTION u8 noncache_buffer[DATA_BUFFER_SIZE];
备注
对于KR4:非缓存属性仅能通过 MCCA寄存器 配置,因此无法直接通过宏定义实现非缓存缓冲区。
对于DSP:若需操作 DSP 缓存,请参考 Xtensa LX7 Microprocessor Data Book 和 Xtensa System Software Reference Manual 获取详细信息。
在缓冲区定义前添加宏 SRAM_NOCACHE_DATA_SECTION,可定义具有非缓存属性 (Non-Cacheable) 的数据缓冲区。
SRAM_NOCACHE_DATA_SECTION u8 noncache_buffer[DATA_BUFFER_SIZE];
使用DMA时的缓存一致性
当使用 DMA 在内存缓冲区之间迁移数据时,缓冲区的起始地址和结束地址必须与缓存行对齐,以避免缓存数据与内存数据不一致。
例如:若某缓冲区的起始地址位于缓存行的中间位置,且前半部分已被其他程序占用,当其他程序对缓存行执行 Invalidate 或 Clean 操作时,该操作将影响整个缓存行,导致当前缓冲区的缓存数据与内存数据不一致。
备注
DMA 操作地址需独占一个完整的缓存行。可通过以下方式之一定义缓冲区:
malloc()
;该函数会返回一个起始地址为缓存行对齐,并且buffer长度也是缓存行对齐的地址。ALIGNMTO(CACHE_LINE_SIZE) u8 op_buffer[CACHE_LINE_ALIGMENT(op_buffer_size)]
;ALIGNMTO(CACHE_LINE_SIZE) 保证起始地址为缓存行对齐,CACHE_LINE_ALIGMENT(op_buffer_size) 保证长度也是缓存行对齐。
DMA Tx 流程
CPU 分配 Tx 缓冲区
CPU 写入 Tx 缓冲区
建议操作:调用
DCache_Clean()
清理数据缓存配置 DMA Tx 参数
DMA 发送中断处理
DMA Rx 流程
CPU 分配 Rx buffer
执行
DCache_Clean()
确保 Rx buffer 处于 clean 状态;(如果 Rx buffer 处于 clean 状态,可跳过此步骤)小心
此步骤执行的原因是:
对于 Cortex-A32,如果 Cache 中的 Rx buffer 处于 dirty 状态,执行第 5 步
DCache_Invalidate()
将同时执行 clean 和 invalidate 操作,可能会导致意外写入行为。如果 Cache 中的 Rx buffer 处于 dirty 状态,当 CPU 的 D-Cache 满了,CPU 可能会将 Rx buffer 中的脏数据写回内存,覆盖 DMA 已经写入的内容。
配置 DMA Rx 参数
DMA Rx 中断处理
执行
DCache_Invalidate()
确保 Cache 没有残留 旧的 Rx buffer 数据。
小心
此步骤必须执行,原因如下:
对于具有自动数据预取功能的 CPU(如 Cortex-A32 和 DSP),当 CPU 读取 Rx buffer 相邻地址的内容时,CPU 会在后台执行行填充操作,自动将 Rx buffer 的旧值重新加载到 Cache 中。
防止 CPU 在 DMA 处理期间将旧值读入 Cache。
CPU 读取 Rx buffer (DMA Rx 返回的值)