15 指令周期和指令流水线
指令周期
指令周期
指令周期:处理单个指令的过程
- 取指周期:从内存中提取一条指令
- 执行周期:执行所提取的指令
只有当机器关闭,发生某种不可恢复的错误或遇到停止计算机的程序指令时,程序执行才会停止
带中断的指令周期
中断禁止 和 中断允许
间址周期
指令的执行可能涉及一个或多个存储器中的操作数,它们每个都要求一次存储器访问
使用间接寻址,还需要额外的存储器访问
间址周期:把间接地址的读取堪称是一个额外的指令子周期
CPU的任务
- 取指令:CPU必须从存储器(寄存器、Cache、主存)读取指令
- 解释指令:必须对指令进行译码,已确定所要求的动作
- 取数据:指令的执行可能要求从存储器或输入/输出(I/O)模块中读取数据
- 处理数据:指令的执行可能要求对数据完成某些算数或逻辑运算
- 写数据:执行的结果可能要求写数据到存储器或I/O模块
CPU需求:寄存器
- CPU需要在指令周期中临时保存指令和数据
- CPU需要记录当前所执行指令的位置,以便知道从何处得到下一条指令
MBR:存储缓冲寄存器 / 存储数据寄存器(MDR)
MAR:存储地址寄存器
IR:指令寄存器
PC:程序计数器
取完指令之后PC就会加一,而不是等到指令执行完毕
数据流
取指周期
过程描述
- PC通过MAR(因为MAR才和系统总线中的地址总线直连)将当前指令的地址放到地址总线上,控制器发送信号到控制总线告知存储器读取地址上的指令地址(中间省略总线的三次握手等机制),存储器获得了当前指令的地址
- 然后存储器将指令放到数据总线上,MBR读取数据总线上的数据并放到IR(指令寄存器)中
- 取指周期结束,控制器控制PC+1
间址周期
过程描述:
- 操作数在MBR中,MBR将该数据传送给MAR,MAR将数据放在地址总线上(此时传输的是间接地址,目标是获得有效地址)。然后控制器发送信号到控制总线上,存储器读取该信号并从地址总线上读取内容。
- 存储器读取该地址中的内容(有效地址)放到数据总线上,MBR读取数据总线上的信息
中断周期
过程描述
-
控制器发送信号给PC,PC将其存放的内容(即下一条指令的地址)放到MBR中,MBR将该内容放到数据总线上。
-
控制器向MAR发送信号,MAR将PC内容在存储器中保存的地址放到地址总线上
-
控制器发送信号到控制总线,存储器读取该信号,读取地址总线上的地址和数据总线上的内容,在该地址中存放PC的内容(即数据总线上的内容)
这里一般会压在栈顶,通过CPU内部的栈指针寄存器我们可以知道栈顶的地址,然后控制器会控制MAR将该地址传送到地址总线上,从而使得中断周期执行完的时候程序可以返回到原来的地方
指令流水线
流水处理(pipelining)
如果一个产品要经过几个制作步骤,通过把制作过程安排在一条装配线上,多个产品能在各个阶段同时被加工
指令流水线:一条指令的处理过程分成若干个阶段,每个阶段由相应的功能部件完成
两阶段方法
将指令处理分成两个阶段:取指令和执行指令
在当前指令的执行周期期间取下一条指令
问题:
- 执行时间一般要长于取指时间
- 主存访问冲突
- 条件分支指令使得待取的下一条指令的地址是未知的
六阶段方法
为了进一步的加速,流水线必须有更多的阶段
- 取指令(Fetch instruction, FI):读下一条预期的指令到缓冲器
- 译码指令(Decode instruction, DI):确定操作码和操作数指定符
- 计算操作数(Calculate operands, CO):计算每个源操作数的有效地址
- 取操作数(Fetch operands, FO):从存储器取出每个操作数,寄存器中的操作数不需要取
- 执行指令(Execute instruction, EI):完成指定的操作。若有指定的目的操作数位置,则将结果写入此位置
- 写操作数(Write operand, WO):将结果存入存储器
各个阶段所需要的时间几乎是相等的(但并没有完全相等)。
不是所有指令都包含6个阶段
- 例:一条LOAD指令不需要WO阶段
- 为了简化流水线硬件设计,在假定每条指令都要求这6个阶段的基础上来建立时序
不是所有阶段都能并行完成
- 例:FI/FO/WO都涉及存储器访问
若6个阶段不全是相等的时间,则会在各个流水线阶段涉及某种等待
限制:
-
条件转移指令能使若干指令的读取变为无效
-
中断 – 流水线失效
流水线性能
假设
- :流水线第 段的电路延迟时间
- :最大段延迟(通过耗时最长段的延迟)
- :指令流水线段数
- :锁存延时(数据和信号从上一段送到下一段所需的段间锁存接收时间)
周期时间
令 为 阶段流水线执行所有 条指令所需的总时间,那么:
加速比:
- 误解:流水线中的阶段数越多,执行速度越快
- 原因:
- 在流水线的每个阶段,将数据从一个缓冲区移动到另一个缓冲区以及执行各种准备和传递功能都涉及一些开销
- 处理内存和寄存器依赖以及优化管道使用所需的控制逻辑数量随着阶段的增加而急剧增加
流水线冒险
在某些情况下,指令流水线会阻塞或停顿(stall),导致后续指令无法正确执行。
类型
-
结构冒险(Structure hazard)/ 硬件资源冲突
也叫资源冒险(resource hazard)
-
数据冒险(Data hazard)/ 数据依赖性
-
控制冒险(Control hazard)
结构冒险
原因:已进入流水线的不同指令在同一时刻访问相同的硬件资源
解决:使用多个不同的硬件资源,或者分时使用同一个硬件资源(分时复用,上升沿和下降沿交给不同的指令)
Cache的引入和数据Cache与代码Cache
数据冒险
原因:未生成指令所需要的数据
解决方案:
-
插入
nop
指令,即什么都不做的指令,让需要前面数据的指令延时进行坏处:时间的浪费
-
插入bubble(硬件控制)
坏处:时间的浪费
-
转发(forwarding)/ 旁路(bypassing)
将
ALU
得到的结果就直接用于接下来的指令。(只能用于后面所用的数据时前面用ALU
计算而出的不足:无法解决
LOAD
指令所带来的问题 -
交换指令顺序
控制冒险
原因:指令的执行顺序被更改
- 转移(Transfer):分支(branch),循环(loop),…
- 中断(Interrupt)
- 异常(Exception)
- 调用 / 返回(Call / Return)
解决:取多条指令
- 多个指令流:复制流水线的开始部分,并允许流水线同时取这两条指令,使用两个指令流
- 预取分支目标:识别出一个条件分支指令时,除了取此分支指令之后的指令外,分支目标处的指令也被取来
- 循环缓冲器:由流水线指令取指阶段维护的一个小的但极高速的存储器,含有 n 条最近顺序取来的指令
问题:多次分支会导致流水线数目不断增长膨胀,无法控制
解决:分支预测
- 静态预测
- 预测绝不发生
- 预测总是发生
- 依操作码预测
- 动态预测
- 发生 / 不发生切换
- 转移历史表
16 控制器
寄存器分类
- 用户可见寄存器
user-visible register
允许编程人员通过机器语言或汇编语言访问,通过优化寄存器的使用而减少对主存的访问
- 控制和状态寄存器
control and status register
-
由控制器来控制CPU的操作,并由拥有特权的操作系统程序来控制程序的执行
-
大多数控制和状态寄存器在大多数机器上是用户不可见的
某些在控制或操作系统模式下执行的机器指令是用户可见的
Tips: 两者的区分并不严格
用户可见寄存器
-
通用寄存器 (general-purpose register)
可被程序员指派各种用途
-
数据寄存器 (data register)
仅可用于保存数据而不能用于操作数地址的计算
-
地址寄存器 (address register)
可以使自身有某种通用性,或是专用于某种具体的寻址方式
例如:段指针,变址寄存器,栈指针
-
条件码寄存器 (condition codes register) / 标志 (flag) 寄存器
CPU硬件设置这些条件位作为操作的结果
至少是部分用户可见的
并非所有机器都有
设计出发点
使用完全通用的寄存器还是规定各寄存器的用途
寄存器数量
- 太少的寄存器会导致更多的存储器访问
- 太多的寄存器又不能显著地减少存储器访问
寄存器长度
- 应该要能保存大多数数据类型的值
- 某些机器允许两个相邻的寄存器作为一个寄存器来保持两倍长度的值
保存和恢复
子程序调用会导致自动保存所有用户可见的寄存器,并在返回时自动取回
- 这些保存和恢复是作为调用和返回指令执行功能的一部分,由CPU完成
- 这允许各个子程序独立地使用用户可见寄存器
子程序调用之外保存用户可见寄存器的相关内容是程序员的责任,需要在程序中为此编写专门的命令
控制和状态寄存器
- 程序计数器(Program counter, PC)
- 存有待取指令的地址
- 通常在每次取指令之后,PC的内容即被CPU更改,转移或跳步指令也会修改PC的内容,因此总指向被执行的下一条指令
- 指令寄存器(Instruction register, IR)
- 存有最近取来的指令,在其中分析操作码和操作数
- 存储器地址寄存器(Memory address register, MAR)
- 直接与地址总线相连,存有存储器位置的地址
- 存储器缓冲寄存器(Memory buffer register, MBR)
- 直接与数据总线相连,存有将被写入存储器的数据字或从存储器读出的字,用户可见寄存器再与MBR交换数据
- 程序状态字(Program status word, PSW)
- 一个或一组包含状态信息的寄存器,包含条件码加上其他状态信息
- 包含的字段或标志
- 符号
- 零
- 进位
- 等于
- 溢出
- 中断允许 / 禁止
- 监管
- 指针寄存器:指向附加状态信息的存储器块
- 中断向量寄存器:
- 系统栈指针:
- 页表指针寄存器:
设计出发点
对操作系统的支持
- 某些类型的控制信息是专门为操作系统使用的
- 若CPU设计者对将要使用的操作系统有基本的了解,则寄存器的组织可能在一定程度上为该操作系统定制
控制信息在寄存器和存储器之间的分配
- 一个普遍的做法是将存储器最前面(最低地址)的几百或几千个字用于控制母的
- 在成本和速度之间权衡
微操作
执行程序时,计算机操作是由一系列指令周期组成,每个周期执行一条机器指令
每个指令周期又可以看作是由几个更小的子周期组成
包括:取指,间址,执行,中断
每个子周期由一系列涉及CPU寄存器操作的更小步骤组成,这些步骤称为微操作
取指周期
出现在每个指令周期的开始,将指令从存储器中取出
这里会访问一次主存
间址周期
指令执行前会有一个间址周期,来读取有效地址(注意这里并没有读取操作数)
完成间址周期后,IR的状态与不使用间接寻址方式的状态是相同的,已经为执行周期准备就绪
中断周期
在完成执行周期的时候,确定是否有允许的中断发生,如果有,则出现一个中断周期
微操作分组的原则
-
事件的流动顺序必须是恰当的
例:MAR <- (PC) 必须先于 MBR <- 主存,因为主存读操作需要用到MAR中的地址
-
必须避免冲突
MBR <- 内存 和 IR <- MBR 这两个微操作不应该出现在同一时间里
-
满足上述条件的情况下,所用的单位时间尽可能少
指令周期代码(Instruction Cycle Code, ICC)
-
取指、间址、中断周期各有一个微操作序列,执行周期则对于每个操作码有一个微操作序列
-
指令周期代码:假设一个2位的ICC寄存器,明确CPU处于指令周期的哪个阶段
00:取指,01:间址,10:执行,11:中断
CPU内部总线
- ALU和寄存器都连接到CPU内部总线上
- 为了数据在该内部总线和各寄存器之间传递,内部总线和寄存器之间有门和控制信号
- 控制线控制着数据和系统总线(外部)的交换以及ALU的操作
一时间在CPU内部总线上只能够有一个数据,否则多个数据会混淆起来
不能合并的原因是因为MBR传输和AC传输都需要CPU内部总线,所以两者必须要分时进行
控制器
控制CPU的功能需求
CPU的基本元素:ALU,寄存器组,内部数据通路,控制器,外部数据通路
CPU需要完成的微操作:
- 再寄存器之间传送数据
- 将数据由寄存器传送到外部接口(如系统总线)
- 将数据由外部接口传送到寄存器
- 将寄存器作为输入和输出,完成算术和逻辑运算
控制器的两个基本任务:
- 定序:根据正被执行的程序,控制器使CPU以正确的顺序通过一系列微操作
- 执行:控制器使每个微操作得以完成
控制器的输入
指令寄存器:当前指令的寻址方式和操作码
标志:确定CPU的状态和前一个ALU操作的结果
时钟:控制器要在每个时钟脉冲完成一个或一组同时的微操作
来自控制总线的控制信号:向控制器提供控制信号
例:中断请求
控制器的输出
CPU内的控制信号
- 用于寄存器之间传送数据
- 用于启动特定的ALU功能
到控制总线的控制信号
- 到存储器的控制信号
- 到I/O模块的控制信号
所有的控制信号最终作为二进制输入量直接输入到各个逻辑门上
即到逻辑门上的信号要么是 要么是
控制信号示例:取指周期
- 传送PC的内容到MAR
- 打开 :PC传到MAR
- 由存储器读一条指令装入MBR,并且递增PC
- 打开 :MAR的内容送到地址总线上
- 存储器读控制信号 (图中未体现)送到控制总线上
- 打开 :数据总线上的内容存入MBR
- 控制信号对PC内容加一(指令长度)并把结果存回PC
- 传送MBR的内容到IR
- 打开 :MBR的内容送到IR
控制器的最小特性
控制器只需要知道将被执行的指令和算术、逻辑运算结果的性质(如正负、溢出等),而不需要知道正被处理的数据获得到的实际结果具体是什么
控制器只是以少量的送到CPU内的和送到系统总线上的控制信号来实现控制
控制器的实现
- 硬布线实现(hardwired implementation)
- 控制器是一个组合电路,把输入逻辑信号转换为一组输出逻辑信号,即控制信号
- 微程序实现(microprogammed implementation)
- 控制逻辑是微程序指定的,控制器通过执行微程序里的每一条微指令来实现控制
硬布线实现:控制器输入
标志和控制总线信号:每位都有特定的意义
指令寄存器:
-
通过译码,使每一操作码有一个唯一的逻辑输入
-
译码器有 个输入和 个输出
控制器要考虑变长的操作码,译码器会更复杂一些
时钟:
- 在一个指令周期内控制周期要在不同时间单位发送不同的控制信号
- 使用一个定时器作为控制器的输入,并且控制器在指令周期结束时必须通知定时器以使其重新开始计数(子周期内递增,子周期结束就应该清零)
硬布线实现:控制器逻辑
-
为每个输出的控制信号设计一个关于控制器输入的布尔表达式
-
定义两个新的控制信号 和
:取指周期,:间址周期, :执行周期,:中断周期
(注:乘是与,加是或)
(LDA:LOAD指令,ADD:ADD指令,AND:AND指令)
微程序实现:基本概念和思路
微程序(固件)介于硬件和软件之间
- 设计固件比设计硬件容易,但写固件程序比软件程序困难
- 微指令序列
微指令:每行描述一个时间内出现的一组微操作
基本思路:
- 对于每个微操作,控制器的任务是产生一组控制信号,即控制器发出的每根控制线或开或关(每根控制线由一个二进制数字表示)
- 构造一个控制字,每位代表一根控制线,这样每个微操作能用控制字中的不同的 和 的样式来表示
- 将这些控制字在一起,可以表示控制器需要完成的微操作序列
-
由于微操作序列不是固定的,把控制字放入一个存储器单元中,每个字有自己唯一的地址
-
添加少数几位用于指示条件的真假
若条件位指示的条件为假,则顺序执行下一条指令
若条件位指示的条件为真,则地址字段指向的微指令是将被执行的下一条微指令
-
给每个控制字添加一个地址字段,以指示某种条件为真时,将要执行的下一控制字的位置
-
微程序控制器:任务
微指令定序(microinstruction sequencing)
- 根据当前的微指令、条件标志和指令寄存器的内容,产生下一微指令的控制存储器的地址
- 设计考虑
- 微指令的大小:减小微指令的大小就能节省控制存储器的成本
- 地址生成空间:尽可能地执行微指令
微指令执行(microinstruction execution)
- 产生控制信号:发往CPU内部,送往外部控制总线或其他外部接口
微程序控制器:构成
- 定序逻辑:向控制地址寄存器装入地址,并发出读命令
- 控制地址寄存器:含有下面即将被读取的微指令地址
- 控制存储器:存有一组微指令
- 控制缓冲寄存器:存放被读出的微指令
17 输入输出
外围设备
输入/输出操作通过连接到输入输出模块的各种外部设备完成,这些外部设备提供了在外部环境和计算机系统之间的数据交换,通常被称为外围设备(peripheral device),简称为外设
类型:
- 人可读设备:适用于与计算机用户通信
- 显示器,打印机,…
- 机器可读设备:适用于与设备通信
- 磁带,磁盘,…
- 通信设备:适用于与远程设备通信
为什么不能把外设直接连接到系统总线上
- 外设种类繁多,操作方法多种多样
- 外设的数据传送速度一般比存储器或处理器的慢很多
- 某些外设的数据传送速度比存储器或处理器要快
- 外设使用的数据格式和字长度通常与处理器不同
I/O 模块
通过系统总线或中央交换器和存储器连接,通过专用数据线与一个或多个外设连接。I/O模块是计算机内部系统和外设之间的桥梁
外围设备的接口
- 输入/输出模块的接口以控制、状态和数据信号的形式出现
- 与设备相关的控制逻辑控制外设的操作,以响应来自输入/输出模块的命令
- 缓冲器用于缓存输入/输出模块和外设之间传送的数据
- 缓冲器的大小一般为8位或16位
I/O 模块的功能
处理器通信:
- 命令译码:输入/输出模块接收来自处理器的命令,这些命令一般作为信号发送到控制总线
- 数据:数据是在处理器和输入/输出模块之间经由数据总线来交换的
- 状态报告:由于外设速度很慢,所以知道输入/输出模块的状态很重要
- 地址识别:输入/输出模块必须能识别它所控制的每个外设的唯一地址
设备通信:
- 通信内容包括命令、状态信息和数据
数据缓冲:
- 外设的数据传送速度一般比存储器或处理器的慢得多
- 某些外设的数据传送速度比存储器或处理器要快
控制和定时:
- 处理器会非预期的与一个或几个外设进行通信
- 一些内部资源,如主存和系统总线,是被共享的
- 例如:控制从外设到处理器的数据传送包括以下几个步骤
- 处理器查询I/O模块以检验所连接设备的状态
- I/O模块返回设备状态
- 如果设备运转并准备就绪,则处理器通过向I/O模块发出一条命令,请求数据传送
- 数据从I/O模块传送到处理器
检错:
- 检错并把差错信息报告给处理器
- 差错类型:
- 设备报告的机械和电路故障
- 传输过程中数据位的变化
I/O 模块的结构
外部接口
接口类型:
- 并行接口:多根线连接I/O模块和外设,同时传送多位数据
- 串行接口:只有一根线用于传输数据,每次只传输一位数据
由于并行接口要求每次同时传送,当传输速度和总线长度增加时,总线的时钟频率会受到限制
I/O 操作技术
- 编程式I/O:处理器通过执行程序来直接控制I/O操作,当处理器发送一条命令到I/O模块时,它必须等待,直到I/O操作完成
- 中断驱动式I/O:处理器发送一条I/O命令后,继续执行其他指令;并且当I/O模块完成其工作后,才去中断处理器工作
- 直接存储器读取(Direct Memory Access, DMA):I/O模块与主存直接交换数据,而不需要处理器的干涉。
编程式I/O
- 当处理器在执行过程中遇到一条与I/O操作有关的指令时,它通过发送指令到适当的I/O模块来执行这条指令
- I/O模块将执行所要求的的动作,然后在I/O状态寄存器中设置一些适当的位
- I/O不会中断处理器,因此处理器需要周期性地检查I/O的状态,直到发现该操作完成。
I/O 命令
- 为了执行I/O操作,处理器发送一个指定具体I/O模块和外设的地址,并发送一条I/O命令
- 类型
- 控制命令:激活外设并告诉它要做什么
- 测试命令:测试I/O模块及其外设相关的各种状态条件
- 读命令:使I/O模块从外设获得一个数据,把它存入内存缓冲区
- 写命令:使I/O模块从数据总线获得一个数据,把它传入外设
I/O 指令
-
I/O指令很容易映射为I/O命令,并且两者之间通常是简单的一一对应关系
指令的形式取决于外设寻址的方式
-
编址方式
-
存储器映射式I/O:存储单元和I/O设备有统一的地址空间
能使用大的指令系统,可进行更有效的编程
-
分离式I/O:让总线既有存储器的读线和写线,同时也有输入和输出命令线
-
中断驱动式I/O
- 处理器发送一个I/O命令到模块,然后去处理其他有用的工作
- 当I/O模块准备和处理器交换数据时,它中断处理器以请求服务
- 处理器执行数据传送,最后恢复它原先的处理工作
从I/O模块的角度来看
- I/O模块接收来自处理器的读命令
- I/O模块从相关的外设中读入数据
- 一旦数据进入I/O模块的数据寄存器后,该模块通过控制总线给处理器发送中断信号
- I/O模块等待直到处理器请求该数据为止
- 当处理器有数据请求时,I/O模块把数据传送到数据总线上,并准备另一个I/O操作
从处理器角度看
- 处理器发送一个读命令
- 处理器离开去做其他的事情,并在每个指令周期结束时检查中断
- 当来自I/O模块的中断出现时,处理器保存当前程序的现场
- 处理器从I/O模块读取数据字并保存到主存中
- 处理器恢复刚才正在运行的程序的现场,并继续运行原来的程序
中断允许和中断禁止
响应优先级和处理优先级
例子:假设中断系统中有4个中断源,其响应优先级为 ,处理优先级为 。如果主程序执行时同时发生 和 中断,并且在处理 中断的过程中发生 中断,写出掩码字和所有中断服务程序的过程
注:主程序的优先级是最低的
注:掩码字/屏蔽字:即如果某个中断程序可以对另一个中断程序屏蔽(处理优先级高),则标记为1
过程描述
- 主程序运行时,发生,响应优先级最高的是 ,因此先中断执行 ,因为 也是处理优先级最高的,所以不会被其他中断源所中断
- 执行完 之后,要恢复主程序的现场(这个时间段是中断禁止的),回复完毕之后,响应优先级最高的 率先执行,但因为其处理优先级比 ,低,所以被嵌套中断,然后 执行完后恢复 的现场并继续执行
- 此时 也请求中断,但因为其处理优先级最低,没办法中断 ,因此 执行完后恢复主程序现场,然后被 中断并执行完
设备识别
- 多条中断线:即使有多条中断线可用,每条线上也需要采用其它三种技术中的一种
- 软件轮询:轮询每一个I/O模块来确定是哪个模块发生的中断
- 菊花链:所有的I/O模块共享一条中断请求线,中断应答线采用菊花链穿过这些中断模块
- 独立请求:特定的中断控制器用于阶码和分析优先级
分配优先级
- 多条中断线:处理器仅仅挑选具有最高优先级的中断线
- 软件轮询:模块的轮询次序就决定了模块的优先级
- 菊花链:链接模块次序就决定了模块的优先级
- 独立请求:中断控制器决定
直接存储器读取(DMA)
编程式I/O和中断驱动式I/O的不足
- I/O传送速度受处理器测试和服务设备速度的限制
- 处理器负责管理I/O传送,对于每一次I/O传送,处理器必须执行很多指令
直接存储器存取:无需经过处理器即可直接访问内存的模块
- 处理器通过发送以下信息向DMA模块发出命令:读/写,I/O设备地址,内存中的起始位置,字数
- 处理器继续进行其它工作
- DMA模块将全部数据块,每次一个字,直接将数据传输到存储器或从存储器读出,而无需经过处理器
- 当传输完成时,DMA模块向处理器发送一个中断信号
DMA内存访问
CPU停止法
- 优点:控制简单
- 缺点:影响CPU,没有充分利用内存
- 适用:高速I/O设备的块传输
周期窃取
- 优点:充分利用CPU和内存,及时响应I/O请求
- 缺点:DMA每次都请求总线
- 适用:I/O周期大于存储周期
交替分时访问
-
优点:CPU未停止或等待,DMA不请求总线
-
缺点:CPU周期大于存储周期
DMA配置机制
单总线分离DMA
- 所有模块共享相同的系统总线
- DMA模块使用编程式I/O,通过DMA模块在存储器和I/O模块之间交换数据
- 便宜但低效
单总线集合的DMA-I/O
- DMA逻辑实际上可能是I/O模块的一部分,也可能是控制一个或多个I/O模块的单独模块
- 减少总线周期数
I/O总线
- 使用I/O总线将I/O模块连接到DMA模块
- 多个I/O模块共享DMA,且易于扩展