第七章:输入输出系统
第七章:输入输出系统
除了CPU和主存之外的设备都是外围设备,简称外设。
每个外设都有各自的控制器,也可以称为I/O接口。


机械硬盘(磁盘)
主存的存储速度很快,但是属于易失性存储器,断电后容易丢失,而且每个sRAM造价很高。
所以我们需要外存来长期存取数据。

机械硬盘的构造如下:


位密度:单位长度内存放的二进制数目。
扇区:就是数学意义上的扇形。
| 对比维度 | 低密度存储(恒定扇区数) | 高密度存储(恒定位密度) |
|---|---|---|
| 分区方式 | 将盘面划分为数量相等的扇形区域 | 将盘面划分为弧长相等的扇形区域 |
| 位密度特性 | 内圈位密度高,外圈位密度低磁盘整体位密度不均 | 内外圈位密度保持一致磁盘整体位密度恒定 |
| 扇区数量 | 每个磁道上的扇区数量相同 | 外圈磁道的扇区数量远多于内圈磁道 |
| 优点 | 控制逻辑相对简单(早期技术) | 大幅提升存储容量,更好地利用外圈空间 |
| 缺点 | 存储空间浪费严重(外圈位密度低) | 需要更复杂的磁头和控制算法来读写不同数量的扇区 |


磁盘的平均存取时间
一次存取的时间由三部分时间构成:
- 寻道时间:磁头从当前位置移动到目标数据所在磁道所需的时间
- 旋转等待时间:磁头到达目标磁道后,等待磁盘旋转,使目标扇区转到磁头下方所需的时间
- 数据传输时间:目标扇区位于磁头下方后,实际读取或写入数据所花费的时间
以上三种时间都有最好和最坏情况,只能取平均,作为评判磁盘性能的指标给到消费者。

看一道例题:


磁盘驱动器和控制器
CPU的寄存器很小,需要配合主存来控制磁盘。

CPU的机器字长是4个字节,那么一共512B的数据就需要传128次(我指的是128个周期),数据经过CPU后放到主存这种传输效率是比较慢的。
位于主机和磁盘之间的是磁盘控制器,能够翻译地址。

具体流程如下:

首先,主机通过总线将逻辑块号发送到磁盘控制器翻译地址,同时将主存中的数据的头32位数据传到数据缓冲寄存器。磁盘控制器的电路发出写控制信号,地址翻译模块将翻译后的地址发送到磁盘驱动器进行寻道,完毕后发回结束信号,随即磁头开始定位并匹配,匹配后发回信号,控制器发送写命令,开始读写数据。数据缓冲寄存器的数据送到磁头,主句再将后续的数据经过数据缓冲寄存器写到磁盘。
总结一下:

固态硬盘(SSD)
比机械硬盘更快,但是很贵。
固态硬盘使用半导体材料制成,是高密度非易失。型存储。但是读取能够马上读取,写需要先擦除再写入,写速度和磁盘差不多,而且擦写是有寿命的
固态硬盘是用页和块来分区的,CPU通过硬盘控制器来实现对硬盘的管理。

为了解决擦写寿命短的问题,硬盘控制器引入了磨损均衡,分为两种
- 动态磨损均衡:写入数据时,自动选择较新的闪存块。
- 静态磨损均衡:就算没有数据写入,SSD也会检测并自动进行数据分配,让老的闪存块承担无须写数据的存储任务,同时让新的闪存块腾出空间,承担平常的写操作。
IO模块的通用接口
无论是磁盘还是硬盘以及其他的外设,我们都可以把他们的控制器称作是IO接口。
他们具有一些通用特性,请回忆计网那本书的内容。
主机想要访问某一设备时,IO桥会将目标设备号广播,直到目标外设回应

这意味着IO接口要和主机通讯,IO接口中有数据缓冲寄存器,设备状态寄存器,命令控制寄存器等寄存器用数据总线与主机相连。还有设备选择电路用地址总线与主机相连,还有IO控制电路用控制总线与主机相连。

比如打印机的IO运行模式:

现在需要把主存中的ABC三个字符打印出来。
CPU发送启动命令,打印机命令译码器分析,启动打印机,状态寄存器设置为就绪,随即主存的A暂存在eax寄存器,读出打印机为就绪状态,A和打印命令通过数据总线传送到打印机,译码器分析后打印机开始工作,状态设置为busy,CPU将B传到eax寄存器之后不断检查打印机状态,如果为就绪就继续下一个字母。
循环这个流程,直到完全打印完毕。
IO端口的编址有独立编址和统一编址。
独立编址就是基于总线并独立于主存地址,给每个外设分配一个地址,操作时加上OUT或INSERT等关键词来表示对IO设备的操作。这种方式因为IO设备数量不多,寻址快,但是只有输入输出,灵活性差。
统一编址就是将主存的一部分地址拿出来分配给IO设备,常被精简指令集采用,不需要设置专门的IO指令,只需要经典的访存指令就能满足需求,CPU会自动根据地址的区间来判断具体的操作设备。
IO程序查询方式
我们上个例子说到,打印机忙碌时,CPU不断检查打印机状态,这就是一种独占查询方式,CPU必须干等着,利用率很低,即使实时性无可比拟。
定时查询方式:CPU启动I/O后,返回执行正常程序。同时,一个定时器被设定,每隔固定时间(如每毫秒)产生一次中断,CPU在中断处理程序中查询一次设备状态。利用率较高,但是存在延迟。
我们以鼠标为例子:

再以硬盘为例子:

所以:

但是我们希望时外设自己执行完命令就主动通知CPU,而不是CPU是不是就要去看一样,那样就可以实现并行运行。
就像我希望老师可以在讲完后主动提醒我这节课签到而不是我一直盯着智慧课堂看他签不签到。
IO程序中断控制方式
I/O(输入/输出)程序中断控制方式是计算机管理中一种关键的数据交换机制。它的核心思想是变被动等待为主动通知:CPU启动I/O设备后便可继续执行原有任务,当设备完成操作时主动“打断”CPU,CPU再转去处理这次I/O请求,从而极大提升了工作效率。
初始化与并行工作:CPU执行一条I/O指令,启动外部设备(如磁盘读取)。之后,CPU不再等待,而是立即返回执行其主程序。此时,CPU和设备处于并行工作状态。
中断请求与响应:当设备完成数据准备后,它会通过中断请求线向CPU发出一个中断请求信号。CPU并非随时响应,而是在当前指令执行周期结束时,才会检查是否有中断请求。如果请求有效且未被屏蔽,CPU则会响应中断。
核心处理与数据传送:响应中断后,CPU通过中断向量表自动定位并执行对应的中断服务程序。ISR的核心任务包括从I/O设备的数据寄存器中读取一个字(或字节)的数据,并最终将其存入内存。
收尾与返回:数据传送完成后,ISR中断服务例程会执行中断返回指令。该指令能自动恢复之前保存的现场,使CPU跳回主程序的断点处继续执行
这一次我们以键盘为例

假设当前CPU正在执行某一程序的某条指令D,下一条指令程序的地址是0x1234,也就是说PC里的地址是0x1234。这时你在键盘上输入了一个字母a,字母a被送到数据寄存器中,同时IO控制电路发送高电平刀中断触发器中,随后CPU在执行完毕指令D之后给中断触发器发送一个中断查询信号,看看有没有外设向CPU发送中断请求。随机中断触发器通过控制总线发送中断信号发送到CPU的中断系统,随即CPU知道键盘有新数据产生,现在需要优先处理键盘数据,所以CPU会执行键盘中断程序。将PC中的值0x1234移动到栈内存中,然后将PC的值设置为键盘中断程序的首条指令的地址0x8888,开始执行程序,键盘中断程序将输入的a移动到主存并将其显示到显示器当中。当键盘中断程序结束后,PC再取回存在栈内存中的0x1234继续执行原程序。
网课还讲了打印机和鼠标的例子,但是没有补充
这种方式一些问题,一个是中断触发器分布在多个IO接口中难以管理,而且cpu一次只能响应一次中断请求,这就产生了类似总线总裁的问题。

为了解决这个问题,就有了中断控制器,内置介个中断请求寄存器,接到每个外设的中断触发器中。控制器在接收到CPU的中断查询信号时,会将已接收的中断请求通过中断判优电路排序优先级,再通过设备编码器返回编码后的向量地址(存储地址)。
插播一下跳转,每个子程序的头指令的地址都会放在主存的某个地方并且有一个相应的地址与之对应,比如上图中0x6666对应地址0xCCCC,对应程序打印机中断服务程序。
比如现在鼠标发出一个中断信号,经过判别电路和编码器生成的中断向量地址0x665F,随后PC值会被转移到栈内存,PC值更新为0x665F,执行,跳转到0x8888,执行鼠标中断服务程序。
中断控制的条件和步骤

整个过程分为三部
- 中断识别和判优
- 中断响应
- 中断处理
CPU响应中断是有条件的
- 至少有一个中断请求
- 当前指令刚刚执行完
- CPU处于开中断状态
指令执行完CPU才会发送中断查询信号。
中断识别与判优
CPU执行某一条指令完毕时,中断控制器接收到CPU发送的中断查询请求,内部集合,判优,编码中断请求,并发回到CPU中去。
中断响应
通过中断隐指令完成,中断隐指令不是一个真正的指令,而是CPU一个自动完成的流程。
中断隐指令:
- 关中断
- 一个标志,因为CPU一时间只能处理一个请求,当关中断尾关时,CPU不再接收新的请求。
- 断点与程序状态
- 断点其实就是当前PC的值,处理中断的时候断点会被放到EPC寄存器(MIPS)或者栈内存(x86)中。程序状态将存放在CPU的标志寄存器中去
- 寻找中断服务程序入口地址并跳转
- 就是根据中断控制器传入的向量地址找到中断程序的首条指令的地址
中断处理阶段
中断处理涉及到控制流程的转移,那么就需要关注原来执行的程序A。

鼠标中断服务程序执行完了CPU要回到程序A继续执行,就分为以下几个流程。
- 保护现场
- 在刚进入中断服务程序时,通过软件(如PUSH指令)将当前所有通用寄存器(如EAX, EBX等)和程序状态字的值压入系统堆栈保存 。
- 恢复现场
- 在中断服务程序结束前,通过软件(如POP指令)将之前压栈的寄存器值按相反顺序弹出到原来的寄存器中 。
- 开中断
- 在恢复现场操作之后、执行中断返回指令之前,使用STI等指令将中断标志位重新置位。这通常在中断服务程序的最后阶段进行。
整体流程:

以上描述的是单中断,以下我们探讨多重中断(嵌套中断)
多重中断和中断屏蔽字
多重中断:是指当CPU正在执行某个中断服务程序时,另一个中断源又提出了新的中断请求,而CPU又响应了这个请求,暂时停止正在的中断服务程序,转去执行新的中断服务程序。
多重中断的“关中断”的状态并不是整个中断处理过程中不可改变的,操作系统可以通过软件指令在关键时刻“开中断”,从而允许更高优先级的中断嵌入。
比如,现在是CPU正在运行鼠标中断服务程序,CPU为了能够接收更高级的中断请求将关中断设置为开,随即将鼠标中断服务程序的断电保存到其他地方去,执行键盘中断程序,这就实现了多重中断。

但是这么做就需要保证:只有优先级更高的中断源请求才可以中断比其级别低的中断服务程序,反之则不然。
要完成这个逻辑就需要引入中断屏蔽字。
中断屏蔽字:一组二进制代码,用来控制CPU是否响应某个中断源发出的请求,从而实现对中断处理顺序的精细管理。
比如有以下四个中断源,那就需要完成这样的逻辑

我们就需要这样的中断屏蔽字来实现,在这里,1就是不接受对应外设的中断请求。

那么硬件具体如何实现?

如图,中断控制器内置一个中断屏蔽字寄存器,现在CPU正在执行C的中断服务程序,当B传出中断请求,控制器的判优电路认为B优先级低,CPU不会响应B的指令。如果是A发送请求,那根据判优电路,A的优先级高,C的断电被保存,控制流程转移,开始执行A的中断服务程序。A的中断服务程序执行完后,开始执行C的中断服务程序。
磁盘的中断控制

DMA控制方式
DMA(Direct Memory Access,直接内存访问)是一项重要的计算机技术,它允许外部设备(如硬盘、网卡)与计算机内存之间直接进行数据交换,而无需中央处理器(CPU)频繁介入。
DMA接口可以位于任何外设当中,比如有能力绕过CPU将数据从磁盘直接移动到主存中,从而减轻CPU开销。
DMA接口又名DMA控制器,内部构成是:
- AR:Address Register,主存地址寄存器
- WC:Word Count,字计数器
- BR:Buffer Register,数据缓冲寄存器
- DAR:Device Address Register,设备地址寄存器
- 其他控制逻辑

如图CPU将操作参数传至DMA控制器中后,磁盘准备好一个字的数据传到DMA的BR中,同时发送DMA请求,DMA控制逻辑发送总线申请,主存控制器允许使用总线,DMA发送主存地址和主存读写命令,一个字的数据被传到主存,最后DMA控制逻辑授予磁盘一个DMA周期,主存地址AR和WC也要相应变化,为下一个字做准备。最后发送DMA中断请求,CPU接受后执行DMA中断服务,开始检查传输是否有误等后续工作。
如果有时候DMA准备使用主存时,CPU已经使用主存。这就产生了冲突。
解决的第一种方法就是DMA夺权:DMA就会向CPU提出申请让他取消使用主存让出总线控制权,DMA获取控制器完成数据传输后会将控制权还给CPU。但是这种方法会导致CPU在DMA使用总线时进入什么都不做的空窗期。
第二种是周期挪用:IO设备挪用或者窃取总线占用权一个或几个贮存周期。DMA仅在需要传输数据时“借用”一个或几个总线周期。若CPU不使用总线,则无冲突;若冲突,则DMA优先(这个时候BR已经是满的,IO设备再等会触发BR覆写,原有数据丢失会导致整体传输失败)
第三种是DMA和CPU交替访问:将CPU的工作周期强制分时,一部分专供DMA访存,另一部分专供CPU访存,这样会扩大存储周期