缓存 (Cache)

IC:

概述

各个 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

片内缓存支持 Enable/Disable、Flush 和 Clean 操作。在 main() 函数之前,各个 CPU 均已调用 Cache_Enable() 启用了 Cache。

操作

描述

I-Cache

D-Cache

Enable/Disable

启用或禁用缓存功能

Flush (Invalidate)

  • 清空缓存

  • D-Cache 可通过地址清空

  • 可用于 DMA 接收后,清空 D-Cache 后,CPU 从 DMA 缓冲区读取数据

Clean

  • 清理 D-Cache

  • 将 D-Cache 内容回写到内存

  • D-Cache 可通过地址清理

  • 可用于 DMA 发送前,清理 D-Cache 保证 CPU 将数据写入 DMA 缓冲区

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];

使用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 流程

  1. CPU 分配 Tx 缓冲区

  2. CPU 写入 Tx 缓冲区

  3. 建议操作:调用 DCache_Clean() 清理数据缓存

  4. 配置 DMA Tx 参数

  5. DMA 发送中断处理

DMA Rx 流程

  1. CPU 分配 Rx buffer

  2. 执行 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 已经写入的内容。

  1. 配置 DMA Rx 参数

  2. DMA Rx 中断处理

  3. 执行 DCache_Invalidate() 确保 Cache 没有残留 旧的 Rx buffer 数据。

小心

此步骤必须执行,原因如下:

  • 对于具有自动数据预取功能的 CPU(如 Cortex-A32 和 DSP),当 CPU 读取 Rx buffer 相邻地址的内容时,CPU 会在后台执行行填充操作,自动将 Rx buffer 的旧值重新加载到 Cache 中。

  • 防止 CPU 在 DMA 处理期间将旧值读入 Cache。

  1. CPU 读取 Rx buffer (DMA Rx 返回的值)