控制IO设备的轮询、中断、DMA方式
主要介绍IO设备是什么,以及IO设备的三种控制方式,包括程序轮询控制(Poll)、单/多设备的中断控制(Interrupt)、直接内存访问控制(DMA)
控制IO设备的轮询、中断、DMA方式
一、关于I/O设备
1.1 什么是I/O设备
- 计算机系统中的组件均通过一个互联的网络(Intercnnection Network)被连通在一起
- 每个I/O设备均需要包含可被寻址的位置,这样这些位置才可以被通过指令访问,这些位置被实现为I/O寄存器
1.2 内存映射I/O设备
Memory-Mapped IO
- 这种I/O设备与内存共享同一个地址空间,共享相同的指令集(不存在特殊的专门指令),所以I/O和Read/Write是一样的(注意I对应Read,O对应Write),这使得操作系统可以把这类设备中的存储器当作普通的内存来进行访问
- Load R2, DATAIN:将输入设备的寄存器中的值Read到处理器的R2寄存器中
- Store R2, DATAOUT:将处理器的R2寄存器内的值Write到输出设备的寄存器中
- 这种方式的优点就是可以共享指令集,缺点就是会挤占内存可用的地址空间
1.3 隔离I/O设备
Seperated I/O, Isolated I/O
- 这种I/O设备采用与内存相隔离的地址空间,并采用自己特殊的指令来进行数据的读写
- 优点:I/O设备仅需要处理更短的地址编码(因为如果和内存共享的话就必须采用内存的地址编码格式,而内存容量大所以编码更长)
- 缺点:隔离的地址空间并不意味着物理意义上的隔离
1.4 I/O接口
- 电脑的I/O外设(Peripheral)种类繁多,会导致不同的数据量、访问速度(这些设备的读写均慢于CPU于RAM)和指令格式,所以他们需要I/O接口(I/O Interfaces)来与计算机进行沟通
- I/O设备接口是一个处于设备与Intercnnection Network间的电路,它提供数据的传输方法、以及状态与控制信息的交换,接口内的数据、状态和控制寄存器可以被Load和Store指令访问
二、I/O控制方式
2.1 程序轮询控制
2.1.1 背景引入
- 假设我们需要处理键盘输入字符并显示的问题,就需要先读取键盘的输入,将其存储在内存中,然后将其显示在屏幕上
- 程序控制方式(Program-Controlled I/O)指的是上述流程中的所有操作均由程序完成,这个过程中需要确保每个操作执行的时机并同步数据传输,这就需要控制信号
2.1.2 状态信号与轮询
- 假设I/O设备可以发送”准备就绪”的控制信号到CPU中,以键盘为例
- 键盘发出信号表示字符可以被读取,此时CPU就会调用Load指令访问接口处的相关寄存器
- 显示屏发出信号表示可以进行显示,此时CPU就会调用Store指令输出被显示字符
- 这种信号称为Status Flag(存储在Status Register中),处理器不断轮询(Poll)该信号,直到设备准备就绪才会执行下一步的指令
- 对于键盘来说:
- 如下图所示,其中键盘的Status Register处于0×4004地址处,包含八位Status Flag,假如KIN信号表示键盘的输入可以被读取,那么CPU在不断轮询KBD_STATUS寄存器的过程中就会检测KIN信号的值,其为1时CPU才可以对KBD_DATA寄存器中的数据进行读取
- 每当输入一个字符后,就会将字符存入KBD_DATA寄存器中并设置KIN信号的值为1,当KBD_DATA寄存器的值被读取走后再将KIN设置为0
- 对于显示屏来说:
- 每当前一个字符显示完毕后,将DOUT设置为1,待新的显示字符被存入显示屏相关寄存器的DISP_DATA处后,再将DOUT设置为0然后执行显示操作
- 对于键盘来说:
2.1.3 轮询的等待循环
- 轮询过程被实现为等待循环(Wait Loop),继续以键盘输入的轮询为例
- 第一步:读取状态寄存器数据到CPU的R4寄存器
- 第二步:将R4寄存器与立即数
0000 0010
做与运算(键盘的状态寄存器大小为8bit,输入状态信号在第二bit处) - 第三步:如果经历与运算后的R4寄存器的值为0,则跳转循环执行第一步(READWAIT)
- 第四步:若未跳转而是执行到了此处,则可以读取KBD_DATA中的输入数据
- 显示屏的输出的轮询等待循环则如下图所示
- 第一步:读取状态寄存器到R4寄存器
- 第二步:显示屏中控制可否输出的是第三位的DOUT位,故要与立即数
0000 0100
做与运算 - 第三步:条件分支循环执行等待循环
- 第四步:将需要被显示的数据(被存储在R5寄存器)存储到显示器的DISP_DATA寄存器内
2.1.4 RISC的轮询程序
- 假设RISC中的键盘读取程序使用轮询来读取一行字符,然后显示一行字符,回车键(CR)的输入被作为程序终点,假设LOC表示输入的第一个字符的被存储在主存中的地址,则该程序如下所示
2.2 单设备中断控制
2.2.1 中断的概念
- 程序执行过程中的中断(Interrupt)指的是在处理器接收到中断信号后,执行完当前未完成的指令后暂时停止原本程序的执行,转而执行一个插入的例程,完成后再返回
2.2.2 中断请求与确认
- 中断控制中,I/O设备准备就绪后才会向CPU发送一个硬件信号请求(Interrupt Request),这使得CPU无需像轮询那般不断查询I/O设备的状态寄存器,从而避免产生无意义的消耗
- CPU在收到请求后会中断当前程序,然后向最高响应优先级的I/O设备发送中断确认(Interrupt Acknowledge)信号来同步双方的状态信息,这是硬件层面的实现
- 中断请求的发出是靠设备状态寄存器中的IRQ信号位控制,这与IN信号位不同,后者是被动等待CPU进行轮询检查的,而前者是控制是否主动发送中断请求的
2.2.3 中断服务程序
- 中断响应过程中,CPU必须在有多个中断请求出现的情况下,选择响应优先级最高的中断,然后CPU才能调用对应中断服务程序(Interrupt-Service Routine/Interrupt Handler)继续中断处理
- 中断延迟(Interrupt Latency)指的是从CPU开始中断(即发生中断响应)到相应的中断服务程序被调用之间的时间差,这个时间差越短越好
- 中断服务程序与子程序(Subroutine)的区别在于调用前后对数据的改变与否
- 正常的程序执行过程中调用子程序函数时:由于调用子程序会对当前存储器(例如主存和CPU寄存器等)的内容带来的潜在改变,而这个改变正是我们所需要和接受的
- 正常的程序执行过程中被中断后调用中断服务程序时:我们不希望在中断停止后恢复正常程序运行后,中断后的存储器状态和中断前的状态存在差异,所以在调用中断服务程序之前需要对可能被改变的数据(即正常程序与中断服务程序共用的数据,例如PC等)进行备份,并在结束中断后进行恢复
2.2.4 中断处理流程
- 中断处理的流程如下图所示,程序收到中断请求后会(在完整完成当前执行的指令后)停止当前程序运行,在合适的时候返回中断确认信号,备份重要数据,然后执行相应的中断服务程序,最后恢复数据备份
- 中断确认除了可以在硬件层面上返回一个信号以实现外,还可以在(软件层面的)中断服务程序过程中修改Device Interface中的某个状态寄存器,以隐性地提示发出中断请求的设备其中断请求已被确认
2.2.5 中断的启用与禁用
- 对于处理器端
- 由于中断随时可以发生,程序执行的中断会破坏一些指令执行的连续性,而程序中的某些指令序列是不应当被中断的(比如当执行从中断恢复到正常程序的过程中,需要进行数据恢复,这个过程中不应当再发生中断,否则存放备份数据的地方就会被新的备份覆盖而导致数据丢失)
- 所以应当在不应被中断的指令序列执行过程中,禁用中断(Disabling Interrupts)以保护,实现方式为在程序状态寄存器中设置一位Interrupt-Enable Bit(IE)
- IE=1时,中断请求可以被响应
- IE=0时,所有中断请求均被忽略
- 对于I/O设备端,在接口处需要有一种机制来规定设备是否具备发出中断请求的权限能力,这也可通过设置一个IE位来实现
2.3 多设备中断控制
2.3.1 识别中断源
- 多中断请求线(Multiple Interrupt-Request Lines):为每个设备提供独立的中断请求线,这种方法可扩展性差、当设备较多时电路布局复杂、硬件成本增加、优先级管理困难
- 共同中断请求线(Common Interrupt-Request Line)指的是所有中断源设备共享同一根中断信号传输线,分为以下两种实现方式
- 向量中断(Vectored Interrupt):中断源设备在向处理器发出中断请求的同时,还会发送一个中断向量代码使得处理器可以确定中断源
- 中断向量(Interrupt Vector)是指向中断源对应的中断服务程序的地址
- 中断向量表(Interrupt Vector Table)中储存着该系统中所有的中断向量
- 中断向量代码(Interrupt Vector Code)是中断向量表中的某个元素对应的索引
- 非向量中断(Non-vectored Interrupt)即轮询(Polling):处理器逐个检查每个设备的状态寄存器的IRQ位,以确定哪个设备发出了中断请求,该方法适用于中断源较少的小型系统
- 向量中断(Vectored Interrupt):中断源设备在向处理器发出中断请求的同时,还会发送一个中断向量代码使得处理器可以确定中断源
2.3.2 同时中断
- 同时中断(Simultaneous Interrupt)解决的是当CPU同时接收到多个中断请求时,该如何选择接收哪个中断请求,有两种解决方法
- 独立中断请求线:每个中断源都和CPU间有独立的中断请求与中断确认线,CPU仅需对比选择响应优先级最高的那根线发送过来的中断请求即可
- 共享中断请求线:
- 软件轮询(Software Poll):处理器逐个轮询检查每个设备的状态寄存器,过程中先遍历到哪个发送了中断请求的就先处理谁,轮询顺序(软件决定)就代表优先级
- 硬件轮询(Hardware Poll)或菊花链(Daisy Chain):设备按空间顺序连接,谁更靠近处理器谁就有更高的优先级
- 优先级组(Priority Group):将设备分组,每个组有单独的中断请求线,组内通过软件轮询或菊花链来确定组内优先级
2.3.3 中断嵌套
中断嵌套解决的是CPU该如何处理已经在执行中断服务程序时接收到的新中断信号,这与同时中断所解决的并不是同一个问题
- 单级中断(Single-Level Interrupt)指的是当一个中断服务程序被执行时,禁止其它中断请求
- 多级中断(Multi-level Interrupt)又称中断嵌套(Interrupt Nesting),指的是一个中断服务程序被执行的过程中,允许CPU接收其它更高优先级的中断信号,这会使得CPU中断当前的中断服务程序然后得以处理另一个新的中断服务程序
- 多级优先级(Multi-Level Priority)系统为处理器和每个设备分配优先级,处理器只接受优先级高于自身的设备的中断请求
- 处理器的优先级(编码在CPU状态寄存器中的若干位上)等于其正在执行的程序的优先级
- 处理器仅会接收比自己具有更高优先级的设备发出的中断请求,然后执行新的中断服务程序,处理器优先级也会继而被抬升至新的更高优先级
2.4 直接内存访问控制
2.4.1 关于DMA
- 前面讲到了程序轮询控制和中断控制,二者都是CPU为外界I/O设备执行服务程序的方式,但这些方法都需要CPU的活跃参与,使得CPU占用较大,并且由于CPU处于存储器层级结构上层,数据传输流量相对有限
- 直接内存访问(DMA, Direct Memory Access)可以提供外设与存储器之间(以及存储器与存储器之间)的高速数据传输,无需任何CPU的参与,其核心思想就是让DMA控制器(DMAC, DMA Controller)代替CPU以接管整个系统的运行,这同时也减轻了CPU的负担并提高了其利用率
2.4.2 DMA操作流程
- CPU预备阶段:CPU将数据传输的相关信息传递给DMAC
- 数据在设备和内存中的位置
- 传输的数据块大小
- 传输方向与传输模式
- DMA控制阶段:当设备准备好传输数据时,DMAC接管系统总线以控制数据传输,CPU则继续执行其他任务
- I/O中断阶段:数据传输完成后,DMAC向CPU发送中断信号,通知CPU传输结束
2.4.3 DMAC主要功能
- DMAC会在被CPU授予权限后接管I/O设备与内存间的数据总线,DMAC在数据传输时会:
- 提供被传输数据的对应内存地址
- 提供控制数据传输的总线信号
- 递增内存地址以进行连续Word传输
- 记录已传输的数据量
- DMA接口中的寄存器示意如下图
2.4.4 DMA传输模式
- 突发模式(Burst Mode)又称块模式(Block Mode):DMAC获得总线控制权后,在返还控制权限之前,一次性传输整个数据块的所有数据,这常被用于加载程序或文件到内存中
- 优点:数据传输效率高
- 缺点:占用CPU较长时间,这期间CPU处于非活跃状态,这使得CPU利用效率降低
- 周期窃取模式(Cycle Stealing Mode):DMAC每次请求获取权限后仅传输一个字节,然后返还控制权限,该模式下会连续发出请求,直到传输完整个数据块为止
- 缺点:数据传输效率较低
- 优点:对CPU执行程序的连续性影响较小
- 透明模式(Transparent Mode):DMAC在CPU不使用总线时才进行数据传输,该模式下DMAC无需请求控制权限
- 优点:对CPU影响最小,CPU不会中断程序运行
- 缺点:硬件实现复杂,成本较高
2.4.5 DMA配置方式
- 共享总线,独立DMA控制器(Single-Bus, Detached DMAC)
- 每个DMAC控制单个I/O设备
- 每次数据传输需要使用总线两次(从I/O设备到DMA,从DMA到内存)
- CPU被挂起两次(将权限分出并中断程序运行两次)
- 共享总线,集成DMA控制器(Single-Nus, Integrated DMAC)
- DMAC可以控制多个I/O设备
- 每次数据传输仅需使用总线一次(从DMA到内存)
- CPU被挂起一次
本文由作者按照 CC BY-NC-SA 4.0 进行授权