DMA 控制器微架构:数据如何不经 CPU 自己流动
更新时间:2026-09-12。本文是「集成电路大类 · 芯片设计」**进阶层(intermediate)**数字逻辑第一百零五篇。中断与 DMA 概念讲过 DMA 把数据搬运从 CPU 卸载;这一篇钻进控制器内部,看它需要哪些寄存器、握手、仲裁和描述符机制。FPGA 侧的 AXI DMA/Data Mover、XDM A 架构是同一套思想的具体 IP。
本文要回答的问题
- 一个 DMA 通道至少要有哪些寄存器?为什么外设地址常「固定」而内存地址「自增」?
- 单次、块、突发传输怎么区分,请求-应答握手怎么保证不丢不重?
- 多通道同时请求总线时怎么仲裁?
- scatter-gather 链表描述符是什么,为什么能搬运不连续内存?
- DMA 和 CPU 缓存为什么会互相「看到旧数据」,怎么维护一致性?
一、一个通道的最小寄存器组
每个 DMA 通道本质是一对地址指针加一个计数器和控制/状态:
- 源地址 SAR / 目的地址 DAR:传输两端,可分别配置自增(线性内存)或固定(外设数据寄存器/FIFO,地址不变、只在该地址反复读写);
- 传输长度/计数:剩余字节、突发个数;
- 控制寄存器:方向(M2P/P2M/M2M)、位宽、突发长度、地址增减、中断使能;
- 状态寄存器:忙、完成、错误(总线错误/对齐/描述符坏)。
外设收/发数据通常在一个固定地址的 FIFO 上,所以「内存侧自增 + 外设侧固定」是 ADC 采集、UART/网络发送最典型的配置。
二、握手、突发与通道状态机
DMA 是总线主设备:外设通过 dma_req 说「我有/能收数据」,控制器在获得总线授权后发起 AHB/AXI 读再写,并用 dma_ack 告诉外设本次握手完成。一个块传输通道的主状态机:
IDLE → (软件使能/有请求) 读源突发 → 暂存内部 FIFO → 写目的突发
→ 计数减/地址推进 → 未完则继续 → 完成:置状态、发中断内部小 FIFO 解耦读、写两端速率(可能在不同时钟/总线,引出 CDC/异步 FIFO)。传输粒度分:单次请求传一个(寄存器搬运级别)、突发 burst(一次握手连续传 4/8/16/…拍,充分利用 AXI 总线效率)、块传输(整段长度一次完成)。多通道请求总线时用固定优先级或轮询仲裁,高带宽的网络/显示通道常配大突发和高优先级。
三、描述符、散聚与双缓冲
简单 DMA 一次只管一段连续内存;真实 I/O(网卡包、磁盘块)数据在内存里不连续。scatter-gather(散聚)把多段传输写成一串描述符(descriptor)放在内存:每项含源地址、目的地址、长度、下一项指针/使能位。控制器使能后自己去内存取描述符执行、顺着链表走,直到末项,CPU 只在开头写一次描述符环和首指针。这与 CPU 取指执行很像,也天然配合环形描述符环 + 半完成/完成中断实现乒乓双缓冲:DMA 填缓冲区 A 时软件处理 B,互不等待。
四、缓存一致性:DMA 最隐蔽的坑
DMA 直接读写内存,绕过 CPU 缓存,于是:
- DMA 从设备写内存后 CPU 读(P2M/收包):CPU 缓存里可能是旧行,必须先 **invalidate(作废)**相关缓存行;
- CPU 写内存后 DMA 读发出去(M2P/发包):CPU 新数据可能还停在缓存脏行没写回,必须先 clean/flush(回写);
- 有硬件一致性互连(CCI/CHI,见 MESI)时由总线监听自动维护,软件免维护;无一致性(多数 MCU、FPGA 裸系统)则驱动必须手动 cache 维护或把 DMA 缓冲放在 non-cacheable 区。
其它坑:地址/长度要满足突发和对齐要求(非对齐 AHB 报错或拆拍)、不能跨页/跨突发边界、调试时 DMA 与单步 CPU 视角不同、低功耗下需时钟和请求保持。
与现有篇目的衔接
- 前置:中断与 DMA 概念、AHB/APB 桥、AXI 基础
- 配套:异步 FIFO/CDC、轮询仲裁、MESI 缓存一致性
- 相关:FPGA AXI DMA/Data Mover、XDMA/PCIe DMA 架构、存储体/乒乓
总结
一句话总结:DMA 控制器是一个能主动发起总线事务的主设备,内部每个通道由源地址、目的地址、长度计数和控制状态寄存器构成,内存侧地址按拍自增而外设 FIFO 侧地址固定,通道状态机在软件使能或外设请求后循环执行「读源突发到内部 FIFO、写目的突发、推进地址和计数、完成后置状态发中断」,内部 FIFO 同时承担两端速率和跨时钟域解耦;传输按粒度分为单请求、突发和块,多通道用固定优先级或轮询在总线上仲裁;scatter-gather 把不连续的多段传输写成内存中带源/目的/长度/下一指针的描述符链表,控制器像取指一样自动取描述符执行,配合环形描述符和半完成/完成中断实现 CPU 与 DMA 交替工作的乒乓双缓冲;最隐蔽的工程问题是 DMA 绕过 CPU 缓存导致的不一致——设备写入内存后 CPU 读到旧行需先 invalidate、CPU 写入待发数据停在脏缓存行需先 clean 回写,具备缓存一致互连时由 MESI 监听自动维护、否则驱动手动维护或使用 non-cacheable 缓冲;此外还要满足地址长度对齐和突发边界约束。