
1. 从一道408真题说起DMA到底在考什么如果你正在准备计算机408统考或者本科学计算机组成原理DMA这个知识点你一定绕不过去。它几乎每年都以选择题或大题的形式出现而且出题角度越来越刁钻——不是简单问你“DMA是什么”而是给你一个具体场景让你判断数据通路、总线占用、中断响应时机这些细节。2024年那道45题就是典型题目给了一个DMA控制器与CPU共享总线的结构问你在DMA传输过程中CPU能不能访问主存、什么时候响应中断、周期窃取发生在哪个阶段。很多同学看完题就懵了因为课本上讲DMA只有薄薄两页根本不够应付这种综合题。我当年复习到这里的时候也卡了很久。后来把唐朔飞、白中英、王道几本教材对照着看又翻了不少实际芯片手册比如STM32的DMA控制器、Linux内核的DMA API才真正把“DMA方式”从考试知识点变成脑子里能跑起来的东西。这篇文章就是把我踩过的坑、理清的逻辑、总结的答题套路全部摊开来讲。不管你是为了考研拿分还是想真正搞懂I/O设备与主机之间到底怎么传数据看完应该都会有收获。核心问题其实就一个I/O设备和主机之间传数据除了CPU一条一条搬还有没有更高效的办法DMA就是那个“更高效的办法”。但它的高效不是凭空来的背后涉及总线仲裁、周期窃取、中断配合、地址生成等一系列机制。下面我按“为什么需要DMA → DMA怎么工作 → 三种控制方式对比 → 考试怎么考 → 实际芯片怎么用”这条线把整个知识链条串起来。2. 程序查询和中断方式为什么不够用2.1 程序查询方式CPU被彻底绑死先看最原始的方式。程序查询也叫轮询的思路特别简单CPU不断读取I/O设备的状态寄存器看数据准备好了没有。准备好了就读走没准备好就继续读循环等待。这种方式的致命问题在于CPU的时间完全浪费在“等”上面。假设一个设备每秒产生1000个字节的数据CPU主频是1GHz那么每处理一个字节CPU要花上百万个时钟周期去轮询。真正用于计算的时间可能连1%都不到。更糟糕的是如果有多个设备CPU还得轮流查询每个设备的状态效率进一步下降。从数据通路角度看程序查询方式下数据从I/O设备到主存的路径是设备 → CPU寄存器 → 主存。数据必须经过CPU中转CPU既要负责搬运又要负责计算负担极重。2.2 中断方式CPU被频繁打断中断方式改进了这一点。设备准备好数据后主动发一个中断信号给CPUCPU暂停当前程序跳转到中断服务程序去处理数据。这样CPU不用一直轮询效率提高了不少。但中断方式有个隐藏成本每次数据传输都要经历一次完整的中断响应过程。这个过程包括保存现场程序计数器、寄存器状态等、跳转到中断服务程序、执行数据传输、恢复现场、返回原程序。如果设备传输的数据块很小但频率很高比如一个高速网卡每微秒就产生一个中断CPU就会陷入“中断风暴”大部分时间都在保存和恢复现场真正干活的时间反而很少。而且中断方式的数据通路和程序查询一样设备 → CPU寄存器 → 主存。数据还是要经过CPUCPU仍然是数据搬运工。对于磁盘、网卡这类高速设备这种方式根本扛不住。2.3 瓶颈到底在哪里把这两种方式放在一起看瓶颈非常清晰数据必须经过CPU中转而且CPU要亲自参与每一次数据传输的控制。程序查询是CPU主动等中断方式是设备打断CPU但本质上CPU都没有从“搬数据”这件事里解放出来。那能不能让CPU只负责“发指令”具体的数据搬运交给一个专门的硬件去做这个硬件直接连接主存和I/O设备数据从设备直接进主存不经过CPU。CPU只需要在开始的时候告诉它“从哪搬、搬到哪、搬多少”传输完成后通知CPU一声就行。这就是DMADirect Memory Access直接存储器访问的核心思想。3. DMA控制器的内部结构与数据通路3.1 DMA控制器的组成DMA方式不是软件实现的它需要一个专门的硬件——DMA控制器DMAC。这个控制器通常集成在主板上或者作为外设的一部分。它的内部主要包括以下几个部件地址寄存器存放要访问的主存地址。传输过程中每传一个数据地址自动加一或减一。字计数器记录还剩多少数据要传。每传一个数据计数器减一减到零表示传输完成。数据缓冲寄存器暂存从设备读来或要写到设备去的数据。控制/状态逻辑负责接收CPU的命令、产生总线请求信号、管理传输过程、在结束时发出中断请求。中断机构传输完成后向CPU发出中断信号。这些部件协同工作让DMA控制器能够独立完成数据搬运不需要CPU逐字节干预。3.2 数据通路谁到谁经过谁DMA方式下数据通路的走向取决于传输方向设备到主存比如读磁盘设备 → DMA控制器的数据缓冲 → 系统总线 → 主存。主存到设备比如写网卡主存 → 系统总线 → DMA控制器的数据缓冲 → 设备。关键点在于数据不经过CPU的内部寄存器。CPU和DMA控制器共享系统总线但数据直接在设备和主存之间流动。这就是DMA“直接”二字的含义——直接访问存储器不绕道CPU。3.3 DMA控制器的两种总线连接方式DMA控制器和CPU怎么共享总线有两种典型结构第一种DMA控制器作为总线主设备。DMA控制器和CPU都能发出总线请求通过总线仲裁器决定谁占用总线。当DMA控制器获得总线控制权时它就像CPU一样在总线上发地址、发读写命令完成数据搬运。这种方式下DMA控制器需要具备总线主控能力结构较复杂但效率高。第二种DMA控制器借用CPU的总线周期。DMA控制器向CPU发出“总线请求”HOLD信号CPU在当前总线周期结束后让出总线HLDA信号DMA控制器利用这个空隙完成一次数据传输然后释放总线。这种方式也叫“周期窃取”或“周期挪用”因为DMA控制器偷走了CPU的一个总线周期。考试中经常考的是第二种方式因为它涉及CPU和DMA控制器之间的握手信号容易出细节题。4. 周期窃取、停止CPU访存与交替访存三种DMA工作模式4.1 停止CPU访存简单但浪费这种方式最粗暴DMA控制器一旦开始传输就要求CPU完全交出总线控制权直到整块数据传完才还给CPU。在传输期间CPU不能访问主存只能做那些不需要访存的操作比如执行寄存器之间的运算或者干脆停下来等。优点是控制简单DMA控制器不需要频繁申请和释放总线。缺点是CPU可能长时间无法访存对于需要频繁访问主存的程序影响很大。这种方式适合数据传输量很大、传输时间很短的场景比如磁盘的一次整块读写。4.2 周期窃取细水长流周期窃取的方式更精细。DMA控制器每次只申请一个总线周期传一个数据然后马上把总线还给CPU。CPU在执行指令的过程中如果当前不需要访存DMA就可以趁机“偷”一个周期如果CPU正在访存DMA就等下一个空隙。这种方式对CPU的影响最小因为CPU只是在某些总线周期被“插队”整体执行速度下降不明显。但DMA控制器的控制逻辑更复杂需要频繁申请和释放总线。实际系统中周期窃取是最常用的方式。这里有个容易混淆的点周期窃取偷的是“总线周期”还是“存储周期”严格来说DMA控制器申请的是总线使用权但最终占用的是主存的一个存储周期。考试中如果问“DMA方式下CPU和DMA控制器争用的是什么”答案通常是“总线”或“存储周期”具体看题目语境。4.3 交替访存各走各的路交替访存也叫透明DMA把存储周期分成两部分一部分给CPU一部分给DMA。比如一个存储周期是1微秒前500纳秒CPU访存后500纳秒DMA访存。两者交替使用互不干扰。这种方式下CPU和DMA都不需要申请总线因为时间片已经分好了。优点是效率高、冲突少缺点是需要主存支持更快的访问速度因为每个存储周期被分成了两半实际访问时间减半。这种方式对硬件要求较高实际系统中用得不多但考试中会考概念。4.4 三种方式的对比对比维度停止CPU访存周期窃取交替访存CPU是否停止访存完全停止仅个别周期被占用不停止交替进行DMA控制器复杂度低中高对CPU影响大小很小主存速度要求低中高适用场景大块数据传输通用场景高速缓存配合这张表建议直接记下来选择题经常考“哪种方式对CPU影响最小”或者“哪种方式需要主存速度最快”。5. DMA传输的完整流程从CPU初始化到中断收尾5.1 CPU初始化阶段DMA传输不是凭空开始的。CPU需要先做几件事设置地址寄存器告诉DMA控制器数据要从哪个主存地址开始读或写。设置字计数器告诉DMA控制器要传多少个数据。设置传输方向是设备到主存还是主存到设备。启动设备通过I/O指令启动外设让它准备数据。启动DMA控制器向DMA控制器发出启动命令。这些操作都是CPU通过程序完成的属于“预处理”阶段。一旦DMA控制器启动CPU就可以去执行其他程序了。5.2 DMA传输阶段DMA控制器启动后按照以下步骤循环工作发出总线请求DMA控制器向CPU发出HOLD信号请求总线控制权。获得总线控制权CPU在当前总线周期结束后发出HLDA信号让出总线。发出地址和读写命令DMA控制器在总线上发出主存地址和读写控制信号。传输一个数据数据从设备经DMA控制器写入主存或从主存经DMA控制器写入设备。修改地址和计数器地址寄存器加一或减一字计数器减一。释放总线DMA控制器撤销HOLD信号CPU重新获得总线控制权。判断是否完成如果字计数器不为零继续下一轮如果为零进入结束阶段。这个过程循环执行直到所有数据传完。每一轮传输一个数据或一个字具体取决于DMA控制器的设计。5.3 传输结束与中断处理当字计数器减到零时DMA控制器知道传输完成了。它会做两件事释放总线不再申请总线控制权。发出中断请求向CPU发出中断信号通知传输完成。CPU响应中断后执行中断服务程序做收尾工作检查传输是否成功、处理数据、启动下一次传输等。注意DMA方式下中断只发生在传输结束时而不是每传一个数据就中断一次。这是DMA和中断方式的关键区别之一。5.4 一个容易忽略的细节DMA请求和中断请求的优先级DMA请求HOLD和中断请求INTR是两种不同的信号。DMA请求的优先级通常高于中断请求因为DMA传输是硬件级别的数据搬运如果被中断打断可能导致数据丢失或总线冲突。而中断是软件级别的处理可以稍后响应。考试中如果问“DMA请求和中断请求哪个优先级更高”答案一般是DMA请求。理由就是上面说的DMA传输不能等中断可以等。6. 考试怎么考408真题中的DMA考点拆解6.1 选择题常见考法选择题对DMA的考察主要集中在以下几个角度角度一DMA方式的数据通路。题目会问“DMA方式下数据从设备到主存经过哪些部件”。正确答案是“设备 → DMA控制器 → 主存”不经过CPU。干扰项通常会写成“设备 → CPU → 主存”或者“设备 → 中断控制器 → 主存”。角度二DMA与中断的区别。常见问法包括“DMA方式下CPU是否参与数据传输”“DMA传输结束时通过什么通知CPU”“DMA请求和中断请求的优先级关系”。这些问题的核心就是一句话DMA传输数据不经过CPU但开始和结束需要CPU参与。角度三周期窃取的含义。题目会描述一个场景问DMA控制器在什么时候占用总线、占用多久。关键要理解“周期窃取”偷的是总线周期而且是在CPU不访存的时候偷。角度四DMA控制器的寄存器作用。地址寄存器、字计数器、数据缓冲寄存器各自的功能以及传输过程中它们如何变化。6.2 大题常见考法大题通常会把DMA和中断、程序查询放在一起对比或者给出一个具体的传输场景让你计算时间。典型大题一三种方式传输时间对比。题目给出设备传输速率、CPU主频、中断处理时间、DMA预处理时间等参数让你分别计算程序查询、中断、DMA三种方式下传输一块数据所需的总时间。这种题的关键是分清哪些时间是CPU时间、哪些是设备时间、哪些可以重叠。典型大题二DMA传输过程分析。题目给出一个DMA控制器的结构图问在传输过程中各个信号的变化顺序或者问某个时刻CPU能不能访存、DMA控制器在做什么。典型大题三周期窃取对CPU性能的影响。题目给出CPU执行指令的访存频率问DMA周期窃取会导致CPU性能下降多少。这种题需要计算DMA占用总线的比例然后估算对CPU的影响。6.3 2024年45题的考点还原2024年那道45题考的是DMA方式下CPU与DMA控制器共享总线的细节。题目给出了一个结构图DMA控制器和CPU通过总线连接主存和I/O设备。问题包括DMA传输过程中CPU能否访问主存、DMA控制器何时发出中断请求、周期窃取发生在哪个阶段。这道题的难点在于它没有直接问你“DMA是什么”而是让你在一个具体结构中判断各个部件的行为。很多同学失分是因为没有分清“DMA传输阶段”和“DMA预处理/后处理阶段”的区别。在传输阶段CPU不能访存如果采用停止CPU访存方式或者只能在不冲突的时候访存如果采用周期窃取方式在预处理和后处理阶段CPU正常访存。7. 从课本到芯片STM32和Linux中的DMA实战7.1 STM32的DMA控制器考试知识点的现实版如果你学过STM32你会发现它的DMA控制器和课本上讲的高度一致。以STM32F103为例它的DMA控制器有多个通道每个通道可以独立配置。配置过程就是设置外设地址相当于课本里的设备地址。设置存储器地址相当于课本里的主存地址。设置传输数据量相当于字计数器。设置传输方向外设到存储器或存储器到外设。使能DMA通道相当于启动DMA控制器。传输完成后DMA控制器会产生一个传输完成中断TC中断CPU在中断服务程序里处理后续逻辑。这和课本上讲的“DMA传输结束后发中断通知CPU”完全对应。STM32的DMA还支持“循环模式”传输完成后自动重新开始不需要CPU重新配置。这在ADC多通道采集、串口DMA接收等场景中非常常用。比如你用STM32的ADC采集多个通道的数据可以用DMA自动把转换结果搬到内存数组里CPU完全不用管等采集完一批再统一处理。7.2 Linux内核的DMA API操作系统层面的抽象在Linux内核中DMA的使用被抽象成了一套API。驱动程序开发者不需要直接操作DMA控制器寄存器而是调用内核提供的函数dma_alloc_coherent()分配一块DMA可访问的内存保证CPU和DMA看到的数据一致。dma_map_single()把一块普通内存映射成DMA可访问的地址。dma_sync_single_for_cpu()/dma_sync_single_for_device()在CPU和DMA之间同步数据处理缓存一致性问题。这里涉及一个课本上不讲但实际开发中很重要的问题缓存一致性。CPU访问内存时会经过缓存而DMA直接访问主存不经过缓存。如果CPU刚把数据写入缓存但还没写回主存DMA就去读主存读到的就是旧数据。所以需要软件显式地刷新缓存或使用一致性内存。考试中一般不会考缓存一致性但如果你以后做嵌入式开发或驱动开发这是必须掌握的。7.3 串口DMA接收一个典型的实战场景串口通信中如果每收到一个字节就产生一次中断CPU会被频繁打断。用DMA接收就可以解决这个问题配置DMA通道让串口接收到的数据自动搬到内存缓冲区CPU只需要在缓冲区满或者空闲中断时处理一次。STM32中常用的做法是“DMA 空闲中断”。DMA负责搬数据空闲中断负责检测一帧数据接收完毕。具体配置步骤配置串口为DMA接收模式。配置DMA通道源地址为串口数据寄存器目的地址为内存缓冲区传输方向为外设到存储器。使能串口的空闲中断。在空闲中断服务程序中读取DMA剩余传输数量计算出实际接收到的数据长度然后处理数据。这种方式的效率远高于每字节中断在高速串口通信中几乎是标配。8. 复习DMA时最容易踩的五个坑8.1 坑一把DMA和中断混为一谈很多同学觉得DMA也是一种中断方式只是名字不同。这是错的。中断方式是设备通过中断信号通知CPU来搬数据数据经过CPUDMA方式是DMA控制器直接搬数据不经过CPU。两者在数据通路、CPU参与程度、适用场景上都有本质区别。记住一句话中断方式下CPU是“搬运工”DMA方式下CPU是“指挥官”。8.2 坑二搞不清DMA请求和中断请求的优先级DMA请求HOLD的优先级高于中断请求INTR。原因是DMA传输是硬件级别的如果被中断打断可能导致数据丢失而中断是软件级别的可以延迟处理。考试中如果问“DMA请求和中断请求同时发生时CPU先响应哪个”答案是DMA请求。8.3 坑三误以为DMA传输完全不需要CPUDMA传输过程中CPU不参与数据搬运但传输开始前CPU要初始化DMA控制器传输结束后CPU要处理中断。所以DMA并不是“完全不需要CPU”而是“CPU不需要逐字节参与”。8.4 坑四分不清周期窃取和停止CPU访存周期窃取是DMA控制器每次只偷一个总线周期传完一个数据就还给CPU停止CPU访存是DMA控制器一直占用总线直到整块数据传完。前者对CPU影响小后者对CPU影响大。考试中如果问“哪种方式对CPU影响最小”答案是周期窃取或交替访存取决于题目选项。8.5 坑五忽略DMA控制器的地址寄存器变化DMA传输过程中地址寄存器会自动加一或减一指向下一个要访问的主存地址。这个细节在计算题中很重要。如果题目问“传输完N个数据后地址寄存器指向哪里”你要根据初始地址和传输方向来计算。9. 把DMA放进整个I/O控制方式体系里理解9.1 四种I/O控制方式的演进逻辑计算机组成原理中讲了四种I/O控制方式程序查询、程序中断、DMA、通道。这四种方式不是孤立的而是一条演进线程序查询CPU主动等效率最低。程序中断设备主动通知CPUCPU仍然要搬数据。DMADMA控制器搬数据CPU只负责开始和结束。通道专门的I/O处理机执行通道程序管理多台设备。每一步演进的核心逻辑都是把CPU从I/O控制中进一步解放出来。程序查询把CPU绑在轮询上中断方式解放了等待时间但没解放数据搬运DMA解放了数据搬运但每台设备还需要一个DMA控制器通道则用一台专门的处理机管理多台设备进一步降低了CPU的负担。9.2 DMA在体系结构中的位置从体系结构角度看DMA控制器是连接系统总线和I/O设备的一个桥梁。它既是总线主设备能主动发起总线传输又是I/O设备的控制器能控制设备读写。这种双重身份让它在不经过CPU的情况下完成数据搬运。在考试中DMA经常和总线仲裁、中断系统、存储系统一起考。比如问“DMA控制器申请总线时总线仲裁器如何决定优先级”“DMA传输时CPU的缓存是否需要刷新”“DMA和虚拟内存如何配合”。这些问题需要你把DMA放在整个计算机系统中理解而不是孤立地背概念。9.3 一个综合案例磁盘读操作的全过程假设CPU要读磁盘上的一个文件块整个流程如下CPU通过I/O指令启动磁盘告诉它要读哪个扇区。CPU初始化DMA控制器设置主存目标地址、传输字节数、传输方向设备到主存。CPU启动DMA控制器然后去执行其他程序。磁盘准备好数据后通过DMA请求线向DMA控制器请求传输。DMA控制器向CPU发出HOLD信号请求总线控制权。CPU在当前总线周期结束后发出HLDA信号让出总线。DMA控制器在总线上发出主存地址和写命令把磁盘数据写入主存。地址寄存器加一字计数器减一。DMA控制器释放总线CPU继续执行。重复步骤5-9直到字计数器为零。DMA控制器发出中断请求通知CPU传输完成。CPU响应中断检查传输结果处理数据。这个流程把DMA的预处理、传输、后处理三个阶段都串起来了。如果你能把这个过程完整讲清楚考试中遇到DMA大题基本不会丢分。10. 几个值得深挖的细节问题10.1 DMA传输时CPU能不能访问主存这个问题要分情况回答。如果采用停止CPU访存方式DMA传输期间CPU不能访问主存如果采用周期窃取方式CPU可以在DMA不占用总线的间隙访问主存如果采用交替访存方式CPU和DMA交替访问主存互不干扰。考试中如果题目没有明确说哪种方式通常默认是周期窃取此时CPU可以在DMA传输间隙访存。10.2 DMA控制器中的字计数器是减到零还是减到负一这取决于具体设计。有些DMA控制器在字计数器减到零时表示传输完成有些在减到负一时才完成。考试中如果题目给出了具体设计按题目来如果没有给出通常默认减到零表示完成。这个细节在计算传输次数时容易出错建议做题时先确认题目中的约定。10.3 DMA和虚拟内存的冲突DMA控制器直接访问物理地址而CPU程序使用的是虚拟地址。如果DMA要访问的缓冲区在虚拟内存中被换出到磁盘DMA就会读到错误的数据。操作系统解决这个问题的方法是对DMA缓冲区进行“锁定”pin确保它不会被换出。这个知识点在操作系统课程中会讲组成原理考试中一般不涉及但理解它有助于你建立完整的系统观。10.4 DMA传输的数据宽度DMA控制器一次传输的数据宽度可以是8位、16位、32位甚至更宽。数据宽度越宽传输效率越高但硬件成本也越高。考试中如果题目给出了数据宽度和传输总量你需要计算传输次数。比如传输1024字节数据宽度为32位4字节则需要传输256次。11. 给不同基础读者的复习建议如果你是完全零基础先把课本上DMA那一节读三遍重点理解“数据不经过CPU”这个核心点。然后自己画一遍DMA控制器的结构图标出地址寄存器、字计数器、数据缓冲寄存器的位置和数据流向。最后找两道真题做一下感受一下考试怎么考。如果你已经有一定基础但做题总是出错建议把DMA和中断方式放在一起对比复习。列一张表从数据通路、CPU参与程度、中断时机、优先级、适用场景五个维度对比。然后把周期窃取、停止CPU访存、交替访存三种方式的区别搞清楚特别是它们对CPU性能的影响。如果你是为了考研冲刺建议重点看近五年的408真题中涉及DMA的题目把每道题的考点和陷阱都标注出来。同时注意DMA和总线仲裁、中断系统、存储系统的交叉考点这些是拉开分数的关键。如果你是在做嵌入式开发想真正用好DMA建议直接看芯片手册中的DMA章节然后写一个简单的串口DMA收发程序跑通。理论结合实践理解会深刻得多。STM32的HAL库对DMA的封装比较友好可以从HAL_UART_Receive_DMA()这个函数入手看看它内部是怎么配置DMA控制器的。12. 一个容易被忽略的考点DMA与中断的配合时机最后再强调一个细节DMA传输结束后发出中断请求这个中断请求是在什么时候发出的是在最后一个数据传完之后立即发出还是等DMA控制器释放总线之后再发出标准答案是DMA控制器在字计数器减到零后先释放总线然后发出中断请求。这样做的原因是中断请求需要CPU响应而CPU响应中断需要获得总线控制权。如果DMA控制器不先释放总线CPU就无法响应中断会造成死锁。这个细节在选择题中可能出现问“DMA控制器在传输完成后首先做什么”。正确顺序是释放总线 → 发出中断请求 → CPU响应中断 → 执行中断服务程序。另外DMA中断的优先级通常低于DMA请求的优先级。也就是说如果DMA控制器正在请求总线同时有一个DMA传输完成中断等待处理CPU会先响应DMA请求再处理中断。这是因为DMA请求是硬件级别的实时信号不能延迟。把这些时序关系理清楚DMA这部分的知识就真正扎实了。考试中不管题目怎么变核心逻辑都是不变的DMA控制器独立搬数据CPU只负责开始和结束总线仲裁决定谁占用总线中断负责通知传输完成。抓住这条主线所有细节都能串起来。