DMA 方式

DMA 是整章演化线的终点,也是唯一一种数据不经过 CPU 寄存器的方式。

7.3.2 末尾算出来的那个 说明了问题:中断方式的开销与传送次数成正比,而高速块设备的传送次数太多了。 DMA 的解法很直接——在设备与主存之间开一条不经过 CPU 的通路,让专门的控制器去搬。

理解 DMA 只需要抓住一件事:DMA 控制器在传送期间会变成总线主设备。 本章前面所有的接口都是从设备,只有它例外。而”成为主设备”这件事的全部代价,就是它必须和 CPU 争总线——三种争法就是本节的核心。

机制

DMA 控制器的组成

它同时具有两副面孔:对 CPU 是从设备(被配置),对主存是主设备(去读写)。

部件作用谁写入初值
主存地址寄存器 AR下一个要读写的主存地址CPU 预处理时
字计数器 WC还剩多少个字没传CPU 预处理时
数据缓冲寄存器 BR暂存正在传送的一个字传送中自动
DMA 请求触发器设备准备好了一个字,置 1设备
控制/状态逻辑管理传送、修改 AR 和 WC、发 HRQ——
中断机构块传完后向 CPU 发中断——

AR 与 WC 的联动是本节最实用的一条:

每传送一个字: 整块传完,发中断

有的教材让 WC 从 开始加到 0(用溢出判结束),结果一样,做题时按题目给的初值走。

flowchart LR
    CPU["CPU"] -->|"① 预处理:写 AR、WC、方向"| DMAC["DMA 控制器"]
    DEV["外设"] -->|"② DREQ<br/>我准备好一个字"| DMAC
    DMAC -->|"③ HRQ<br/>总线请求"| CPU
    CPU -->|"④ HLDA<br/>总线响应,CPU 让出总线"| DMAC
    DMAC -->|"⑤ 直接发地址读写"| MEM["主存"]
    DEV <-->|"⑤ 数据"| MEM
    DMAC -->|"⑥ WC=0,中断请求"| CPU

    classDef cpu fill:#e3f2fd,stroke:#1565c0
    classDef dmac fill:#ffcdd2,stroke:#b71c1c,stroke-width:3px
    classDef other fill:#c8e6c9,stroke:#1b5e20
    class CPU cpu
    class DMAC dmac
    class DEV,MEM other

图上的第⑤步是全章唯一一条”设备 ↔ 主存”的直连数据通路。 数据不进 CPU 寄存器——这就是 DMA 与前两种方式的根本分界。

第③④步是 6.1.1 主设备判据的直接应用:DMA 控制器发出 HRQ 申请、CPU 用 HLDA 让出总线之后,发地址的人从 CPU 变成了 DMA 控制器,主设备身份随之易手。“谁发地址谁是主设备”这条判据在这里第一次派上真正的用场。

三种与 CPU 争总线的方式

这是本节的第一考点。三种方式的差别只在于”DMA 一次占用总线多久”。

停止 CPU 访存周期挪用(周期窃取)DMA 与 CPU 交替访存
DMA 一次占多久整块传完才还一个存取周期,传一个字就还把一个 CPU 周期固定切成两半
CPU 停顿长,整块期间不能访存短,只在被挪用的那个周期不停顿,两者各用各的半周期
总线控制权切换一次(开销小)每字一次(开销大)不需要申请,硬连线分时
DMA 吞吐最高中中
硬件复杂度最低中最高
适用高速设备、成批传送最常用,兼顾两者需要专门设计的总线控制逻辑

“交替访存”这一种要特别注意:它不需要申请和归还总线。 总线控制权的划分是预先硬连线定死的——前半周期归 CPU,后半周期归 DMA。所以它没有 HRQ/HLDA 这套握手,也就没有切换开销,代价是硬件必须专门设计。

这条与 6.1.1 的”分时”是同一个概念:交替访存就是把一个周期分时给两个主设备,而分时的划分方式是静态的(预先定死),不是动态仲裁的。

周期挪用的三种情形

“挪用”具体挪的是什么,取决于 CPU 当时在干什么。这是第二考点。

CPU 此刻结果
不访存(在做运算、译码)DMA 直接用,完全没有冲突
正在访存DMA 等这个存取周期结束再用
同时要访存DMA 优先

第三行的理由必须说清楚:DMA 优先不是因为它重要,而是因为它等不起。

外设的数据是流式产生的——磁盘转过去了、网线上的比特过来了,如果 DMA 控制器不及时把数据搬走,缓冲寄存器就会被下一个数据覆盖,数据永久丢失。 而 CPU 晚一个周期访存只是慢一点,没有任何东西会丢。

“损失可恢复的让路给损失不可恢复的”——这是优先级设计的通用原则,与5.5.3 里”故障优先级高于外部中断”是同一条道理。

边界辨析:"周期窃取"窃的是什么周期

窃的是存取周期(总线周期),不是 CPU 的指令周期,更不是 CPU 的运算能力。

说法判断
”DMA 窃取了 CPU 的一个指令周期”❌
“DMA 窃取了一个存取周期 / 总线周期”✅
“DMA 期间 CPU 完全停止工作”❌ CPU 照常执行不访存的操作
”DMA 期间 CPU 一定被延迟”❌ 如果 CPU 恰好不访存,延迟为 0

理解的关键是 CPU 并非每个周期都访存。 取指要访存,取操作数要访存,但译码、运算、写回寄存器都不访存。这些周期正是 DMA 可以”白捡”的。

这也解释了为什么 Cache 命中率高的系统里 DMA 的影响更小——Cache 挡掉了大部分访存请求,CPU 需要用主存总线的周期本来就少。

三个阶段

阶段谁做做什么
预处理CPU(软件)测试设备状态、写 AR / WC / 方向、启动设备
数据传送DMA 控制器(硬件)循环:请求总线 → 传一个字 → AR+1、WC−1,直到 WC=0
后处理CPU(软件,在中断服务程序里)校验数据、处理错误、决定是否继续传下一块、唤醒进程

首尾两段都是 CPU 做的——“DMA 不需要 CPU”这句话只在中间那一段成立。

后处理为什么必须有:DMA 控制器只会搬字节,它不知道传来的数据对不对、要不要重传、哪个进程在等它。这些判断只有软件能做。

DMA 中断与程序中断的两点不同

DMA 结束时也发中断,但这个中断和 7.3.2 的中断有两处实质差别:

程序中断DMA 结束中断
目的为了传送数据数据已经传完了,只为后处理
频率每个字一次每个数据块一次

而 DMA 请求(DREQ/HRQ)与中断请求(INT)的差别更大,这是第三考点:

中断请求 INTDMA 请求 HRQ
要求 CPU 做什么暂停当前程序,转去执行服务程序只借走总线,程序不用停
响应时机一条指令结束后一个总线周期(存取周期)结束后
要不要保存断点要不要(程序根本没中断)
改变 CPU 现场吗改变(PC、PSW、寄存器)不改变
响应更及时的是——DMA(等待粒度更细)

“DMA 响应比中断响应更及时”的完整理由就在第二行:指令可能要好几个总线周期,而 DMA 只需等最小的那一个粒度。

再补一句,DMA 请求的优先级高于中断请求,理由与前面周期挪用一样:数据会丢,而中断可以等。

DMA 与 Cache 的一致性问题

DMA 绕过 CPU 直接读写主存,就绕过了 CPU 的私有 Cache,于是可能读到或留下旧数据。

两个方向各有一个故障:

方向问题原因
DMA 读主存(内存 → 设备)设备读到旧数据CPU 刚写的新值还在 Cache 里(写回法下没写到主存)
DMA 写主存(设备 → 内存)CPU 读到旧数据Cache 里还留着这块地址的旧副本

三种解法:

  1. 不可缓存:把 DMA 缓冲区标记为不进 Cache。简单,但 CPU 访问该区域会变慢。
  2. 软件维护:DMA 之前写回(flush)相关 Cache 行,DMA 之后作废(invalidate)它们。由驱动程序负责。
  3. 硬件一致性(总线侦听):Cache 控制器监听总线上的 DMA 事务,自动作废或更新——这就是 3.5.5 的侦听协议,只不过那里的另一方是别的 CPU 核,这里是 DMA 控制器。

认出这一点很省事:多核之间的 Cache 一致性和 DMA 引起的一致性,是同一个问题的两个来源,解法也是同一套。

性能计算

模板仍与前两节同形,只是”每次”的粒度变成了一整块。

已知:设备传输率 (B/s)、每块 (B)、一次 DMA 的预处理加后处理共 个时钟周期、主频 。

与中断方式的公式一模一样,差别全在 :中断的 是几个字节,DMA 的 是几百上千字节。

另一类常考的是”总线占用”,问的是另一回事:

占用总线的时间比总线带宽

这两个数字要分开答: 是CPU 执行指令的开销,总线占用比是 DMA 抢走的总线时间。同一台设备,前者可能只有 0.01%,后者可能有 20%——CPU 没在为它执行指令,但它确实被 DMA 拖慢了。

接上第 6 章的算例:6.1.5 算过总线的峰值带宽 ,DMA 的总线占用比就是设备速率除以这个值。若多个 DMA 设备并存,占用比相加超过 1 就说明总线成了瓶颈。

边界

说法判断理由
”DMA 完全不需要 CPU”❌预处理和后处理都是 CPU 做
”DMA 传送不产生中断”❌块传完后要中断做后处理
”DMA 控制器始终是从设备”❌传送期间是主设备;被 CPU 配置时才是从设备
”周期窃取窃的是 CPU 指令周期”❌存取周期 / 总线周期
”DMA 期间 CPU 完全停止”❌只有”停止 CPU 访存”方式才接近这样;其余两种 CPU 照常执行不访存的操作
”交替访存需要申请总线”❌预先硬连线分时,无握手
”DMA 数据要先送到 CPU 寄存器”❌直接进主存,这是 DMA 的定义性特征
”中断请求的优先级高于 DMA 请求”❌反了,DMA 优先,因为数据会丢
”DMA 响应比中断响应慢”❌更快,等待粒度是总线周期而非指令
”有了硬件 Cache 一致性就不用管 DMA 了”⚠️一致性解决了,但总线争用仍在
”DMA 方式下 CPU 与外设完全并行”⚠️逻辑上并行,但争总线时仍有物理冲突

对照速查

三种争总线方式DMA 占用CPU 停顿复杂度
停止 CPU 访存整块长低
周期挪用一个存取周期短中
交替访存固定半周期无高
三阶段谁做
预处理CPU
数据传送DMA 控制器
后处理CPU(中断服务程序里)
INTHRQ
响应时机指令结束总线周期结束
保存断点要不要
优先级低高
总线占用比总线

考点

  • 三种争总线方式的对照,尤其”交替访存不需要申请”。
  • 周期挪用的三种情形及 DMA 优先的理由。
  • DMA 请求与中断请求的五点差异——高频大题的送分点。
  • 三阶段的分工:首尾归 CPU。
  • DMA 控制器的主/从双重身份。
  • 性能计算,注意区分 CPU 占用率与总线占用比。
  • Cache 一致性的两个方向及三种解法。

链接