文章目录
外部设备
程序查询方式+程序中断方式(注意数据丢失)
- 数据寄存器:用于存放主机要输出给外设的数据,或者外设要输入给主机的数据
- 控制寄存器:用于记录某一个外设它具体需要做什么动作,比如对于键盘来说,控制键盘上的等亮还是不亮。
- 状态寄存器:反映了当前这个外设的一个状态,比如说这个外部设备它是否在忙碌?或者他是否有损坏或者这个外设是否已经完成了工作之类的。
考点:
1.通过IO设备写入缓冲区的速率求得CPU从缓冲区读取数据的频率
用写入速率(B/s)除以缓冲区的大小(B)求得1秒写入多少次。从而推出一秒至少读取多少次缓冲区
2.求CPU查询时间占比
知道CPU查询一次的时间开销,和一秒需要查询多少次。求出一秒钟查询所需要的时间
当你使用了scanf函数之后,scanf相当于发出了一个系统调用,请求操作系统去读一个字符
这个字符是从键盘输入的,键盘就是你的IO设备。键盘是通过USB接口连接主机的,
在USB的背后,他会有一个芯片,可以理解为,他是集成在你的电脑主板上的,这个芯片就是所谓的IO接口(IO设备的软件部分)
这个IO接口会有不同的类型,不同的IO接口缓冲区大小不同(1B ,1个字,几个字)
对于键盘这种字符型设备来说,敲击键盘,把数据扔到缓冲区里面之后,
假如缓冲区只能存储1个字节,敲一下键盘缓冲区就会被充满。如果你的手速非常快,那么缓冲区里面的数据可能会被覆盖掉
设备以一定的速率将数据放入缓冲区,CPU以一定的频率取走数据放入主存
程序查询方式是CPU先把缓冲区的数据取出到CPU的寄存器里,再由CPU的寄存器写到主存
程序查询方式意味着,一直进行while循环,不断地来查键盘有没有输入。不过CPU并不会被吃死
因为OS会给各个进程分配时间片的,每个进程他的时间片用完了,他就得下处理机
- scanf代码的底层原理:
首先CPU通过控制总线向这个接口发出读的命令。要从中读一个数据,同时可以通过地址总线来指明他要读的是哪一个设备,比如说要从这个键盘读入一个数据。地址总线还有一个作用,可以用于指明此次要从这个设备读入的数据应该放在哪个寄存器,比如说可以指向这个数据寄存器。意思就是说当我们从键盘这个外设输入数据的时候,把它放到数据寄存器里边,好,现在对这个l/O设备的读命令已经发出了。
程序查询方式不会因为While循环而吃死CPU!
CPU会给各个进程分配时间片的,每一个进程他的时间片用完了,那么这个进程他就得下处理机。
- 那如何判断我们要的这个字符数据此时有没有被输入呢?
【程序查询方式】:一个比较容易想到的。很笨的方法就是可以让cpu不断的轮询检查。因为刚才我们说过通过状态寄存器可以检测出此次的I/O操作是否已经完成,如果说此时这个io操作已经完成,那么是不是就意味着我们已经敲击了键盘,并且我们敲击的那个字符数据已经被放到数据寄存器里了?好,所以CPU不断的检查I/O接口内的这个状态寄存器,当它发现l/O操作完成之后就可以通过数据总线取走这个数据寄存器里的值,这样就完成了键盘的输入工作,那刚才我们提出的这种方案是比较傻的,CPU需要不断的去检查这个状态寄存器,它不可以做其他事情。因此你其他那些后台程序的运行都需要暂停。
【程序中断方式】:scanf这一指令会导致CPU向l/O接口发出一个读命令。要从相应的设备读入一个数据,CPU在等待键盘输入的这个过程当中,可以先去执行其他的程序。就不需要一直轮询检查,接下来当你敲击键盘输入了一个字符之后,这个I/O设备会向CPU发出一个中断请求,这个中断请求相当于给CPU打了个电话,告诉他我的工作已经完成了,那CPU接下来会响应这个中断请求,从l/O接口当中取走时已经准备好的数据。因此采用这种程序中断方式就可以解放cpu的工作时间,cpu不需要再陷入忙等。
对于程序中断方式,CPU每执行完一条指令后,都会去检查是否有中断请求。
IO设备向IO接口写入数据,当IO接口的数据缓冲区充满时,IO接口就会给CPU发送一个中断信号,告诉CPU这次中断完成了
CPU检测到这个中断信号之后,对中断信号进行处理(为了把缓冲区中的数据取走)。
中断处理分为两个阶段:1.中断的响应 2.中断的服务
中断响应对应的是中断隐指令这些东西。因为检测到中断信号之后,硬件会自动的触发一系列的骚操作,这一系列的操作就包含中断隐指令
中断隐指令结束之后,PC会跳到中断服务程序,开始做中断的一系列操作(例如保存断点、跳到中断服务程序、返回之前的断点 )
CPU处理完中断信号之后,缓冲区的数据就被取空了,然后IO设备就可以继续写入数据
考点:
1.中断频率
DMA控制方式(不需关注数据丢失)
DMA设备通常是块设备,比如说磁盘
你的磁盘通过USB线连到了你的电脑的USB接口上,当然,我们也可以把它称为DMA接口,
当USB接口连接DNA设备的时候,我们就可以把它认为它是DMA接口。
USB【Universal Serial Bus】通用串行总线,
所以USB接口当他连接字符型设备的时候,你就可以把USB认为是一个字符型的接口,
当它连接DNA设备的时候,你就可以把它认为是DNA设备的接口。
DNA。这大家有一个地方容易混乱,我们都知道DNA设备它是以块为单位跟你的主机进行数据交换,
那是不是意味着你的这个磁盘可以一次往这个DNA接口或者说这个USB接口里面充入一块的数据呢?是不是这样?
DMA设备每一次传输的数据单位是块,但是他这儿的传输指的是他和主机之间的传输
主机指的是主存和CPU,而IO接口他并不是主机。
DMA设备和IO接口之间的传输同样是以字为单位的
那么问题来了?DMA设备和主机之间如何实现按块传送的呢?
首先CPU他要传输一块数据的时候,每一次DMA传输都会有一个预处理and一个后处理
第一步,CPU会进行预处理,他需要一定的时间开销。就是给这个DMA接口发送一些指令,告诉DMA接口要把数据传送到内存的哪个块以及块的地址
接下来DMA设备会在DMA接口的控制下,向主存的相应的块写入数据
(DMA接口和DMA设备之间是以字为单位传送的,同时DMA接口也是一个字一个字的向主存传送数据)
整个块都写完后,DMA接口会给CPU发一个DMA中断信号,CPU检测到这个中断信号之后就会进行处理。处理DMA中断信号的过程叫做后处理
注意:DAM和主存之间传输的是字,当主存块写满之后,才会发出中断信号。
DMA控制方式下,数据不会被覆盖
在进行数据的读写时,CPU会通过io指令向DMA控制器指明此次要读或者要写的数据存放在那儿,应该转存到什么位置,应该转存多大的数据,发出这个l/O指令之后,CPU就可以转去做其他的事情,I/O设备可以慢慢的准备这个数据。I/O设备准备好的数据会先存到DMA控制器当中,那么准备好一个字的内容DNA控制器就会发出一个请求。接下来DMA控制器会占用一个存取周期往【主存】的对应位置写入一个字的数据。那如果说在这个存取周期之内,CPU也想要访问主存,CPU就得先等一等,等DMA控制器写好这一个字的数据之后,CPU才可以继续的往后执行,也就是继续来访问这个主存,因为从图中你可以看到,主存是被CPU和DMA控制器同时连接的。我想到DMA内控制器对主存进行读或写操作的时候,CPU就不能对储存进行读和写。因此DMA控制器每次往主存里写数据的时候,都需要占用一个存储周期。不过值得庆祝的是一个存取周期的时间肯定要比这个CPU执行中断处理程序的时间要更短。
程序中断方式每传一个字,CPU需要运行一次中断处理程序,而下面DMA方式每传一个字需要占用一个存取周期就可以。
那么DNA控制器和主存每次传一个字,但传完了一整块的数据之后,它才会向CPU发出一个中断请求。也就是每传完一整块的数据之后CPU才需要执行一次中断处理程序,因此DMA方式要比程序中断方式效率高。
通道控制方式
通道控制方式的一个工作原理
如果此时CPU向通道指明一个具体的任务,CPU会告诉通道你应该处理的I/O设备是哪一个,另外当通报管理这个l/O设备的时候,应该执行的程序(也就是由通道指令组成的这个通道程序)。这个程序被存放在内存的什么位置?好,接下来通道就可以根据CPU的指示去内存当中一条一条的取出这些通道指令?然后每一条通道指令的执行都会对应着给这个I/O设备发出一个具体的命令。比如通过设备1输入一系列的数据,所以通道再执行这些通道指令序列的时候,就是在对这些I/O设备进行操作,并且具体要进行什么操作,我们可以用编程的方式用这些通道指令来灵活的进行调整。那么当通道执行完这一系列的指令之后,他才会向CPU发出一个中断请求,就是通知CPU它已经完成指定的这一系列任务了。接下来CPU再对这个中断请求进行相应的处理就可以,因此引入通道之后,CPU对l设备繁杂的管理工作又可以进一步的得到解放。
对于之前提到的DNA方式来说,我们只能连续的读入或者写出一整块的数据。每传送完一整块的数据都需要CPU的介入,而引入通道之后,我们对这个数据的存取位置、到底应该输出到哪些设备、或者应该从哪些设备依次的输入,这些控制都可以变得非常灵活,只需要提前编制好通道程序就可以。那只有通道完成了这一大堆工作之后才需要CPU介入一次。
输入设备和输出设备
外存储器
外存储器
磁盘存储器
延迟时间:通常为转半圈所需要的时间
磁盘阵列(关注读写速度and容错能力)
逻辑上相邻的两个扇区在物理上存到两个磁盘,这与低位交叉编址的多体存储器其实是一个思想:
因为磁盘是一种慢速的IO设备。一个很常见的需求就是我们可能会连续的读出很多个逻辑上相邻的数据,那如果说这些逻辑上相邻的数据全部都放在同一个磁盘里,那原来这个磁盘它的读写速度能力有限的,因此我们所有的数据都从同一个磁盘读出,就会导致IO的速度比较慢,但是如果我们把这些数据逻辑上相邻的部分把它们在物理上放到不同的磁盘里边,那么这就意味着第一份数据,我们从零号磁盘读,第二份数据,我们从一号磁盘读,那这样的话,我们读写数据的速度就相当于有两个磁盘在为我们服务。这个可以使得多个磁盘上的数据可以被并行的访问,那这个图里边我们只是给了两个磁盘,事实上我们是不是还可以搞很多个磁盘,比如说这个图四个。
光盘存储器
IO接口(IO端口就是IO接口内部的一些寄存器)
IO接口的作用
IO接口与外设之间传输数据是串行传输
IO接口与CPU之间传输数据是并行传输
IO接口的原理
打印机的工作原理
CPU将命令【一串二进制码】输入到这个【控制寄存器】,即输入【一个字】的信息,那由于这一个字是用来发出具体的命令的,因此这个字称为【命令字】,也有的教材把它称为【控制字】,
每一个设备它所能识别的这个命令字二进制的代码有可能是千差万别的,只有厂家自己知道他们的设备可以识别什么样的命令。因此通常来说发出这个命令字需要设备所对应的【驱动程序的协助】。
发出了命令之后,在io控制逻辑的这个指挥下,就会根据CPU发过来的这个命令字去给对应的这个设备发出一系列的【控制信号】,就是一些电信号。用这样的方式来启动打印机。
那接下来CPU需要从这些【状态寄存器】里边读取状态字。用这种方式来确定设备此时是否已经就绪或设备的工作是否已经完成,都是从这个状态寄存器来查询的,那么对于打印机这个输出设备来说,接下来CPU需要通过这个数据总线往【数据缓冲寄存器】里写入想要打印的数据,然后再在这个【控制逻辑电路】的操控之下,把这些数据逐个的输出到打印机当中,
那打印机完成工作之后就可以给这个IO接口进行一个状态的【反馈】,当IO接口检测到这个设备的工作已完成之后,就会修改【状态寄存器】里边相应的比特位,那这样的话,CPU就可以通过状态寄存器来得知这个IO操作的完成。
如何检查IO设备工作完成
那之前我们还说过CPU可以用一种比较笨的方法,就是用不断【轮询检查】的方法来检查这个状态寄存器。也就是轮巡检查这个lo操作是否完成,
那还有一种比较机智的方法也可以通过这个控制线给CPU发送一个中断请求信号,当CPU检测到中断信号的时候,再来对这个中断进行处理。
为什么把状态寄存器和控制寄存器把它们写在了一起?
通过刚才这个过程的描述,可以看到当CPU要控制一个设备进行输入或者输出操作的时候,一定是CPU先向设备发送一个命令,因此我们可以先把那个命令的信息放到【控制寄存器】当中,那当这个【lO控制逻辑】取出这条命令之后,是不是这个控制寄存器就空闲了?接下来我们没有必要让命令字一直存放在控制寄存器当中,对吧?好另一个方面控制逻辑启动了设备的工作之后,是不是设备需要随时给这个CPU反馈一些工作的状态?因此同样是刚才这个寄存器,我们就可以把它进行重复的利用,可以把设备的状态信息、工作的完成情况这些存放在同一个寄存器里。
所以由于状态寄存器和控制寄存器他们在使用时间上是刚好可以错开的,所以有很多IO接口里边会把这个控制存器与状态寄存器合二为一,只用一个寄存器来完成两个功能。
首先是用于接收CPU发过来的命令字,然后是用于反馈每一个设备的状态字。在时间上是错开的,因此我们才把状态和控制寄存器写在了一起。
那在IO接口内部的这些寄存器就是CPU可以访问的这些寄存器,我们通常把它称为【IO端口】。
比如这个数据缓冲寄存,很多地方会把它称为【数据端口】,
然后状态寄存器会称为【状态端口】,
控制寄存器会称为【控制端口】
那由于IO接口内部会有多个寄存器,也就是有多个端口,因此CPU在对这些端口的数据进行读和写的时候,就需要指明他要读要写的是哪一个端口的信息,所以这就是【地址线】的作用。
CPU会通过地址线来指明他要往哪个寄存器里边读数据或者写数据。比如我们可以给上面这个寄存器编号为零,下面这些寄存器编号为1之类的,当然了lO端口还有其他的一种编制的方式,这个我们一会儿再展开好,另外这个io总线里边包含了数据总线,地址总线和控制总线。地址总线已经说了是用于指明CPU要读写数据的这个IO端口是哪一个?接下来还需要通过控制总线发出读或者写的命令。用于指明对这个端口到底是要读还是要写好,除此之外我们之前也强调过控制总线还会用于给CPU反馈中断请求信号。而对于数据总线来说,CPU要输出的数据或者要从外设输入主机的数据,这些数据都会通过【数据总线】来传送。把它放到数据缓冲寄存器里,那除了输入输出的数据之外,数据总线也会用于传输这个【状态字】,还有【命令字】相关的信息。那再次强调有的教材也把命令字称为【控制字】,所以这些术语都需要知道
最后数据总线还会用于传输【中断类型号】。,比如说我们的一个设备,它的工作已完成。当他【工作完成】的时候,需要发送一个中断?需要CPU进行一个中断的处理?而如果设备【出现了故障】,也需要CPU进行中断的处理。但是工作完成和发生故障两种中断的类型肯定是不一样的,所以为了让CPU知道当前出现了这个中断请求到底应该怎么处理,所以也需要通过这个数据总线。再结合状态寄存器里的内容给CPU反馈一个具体的中断类型号,让CPU知道接下来应该怎么处理。那这就是数据总线,地址总线和控制总线的一个作用
另一个问题大家可能会有疑惑,就是我们刚才说IO接口可以接多个设备。那么CPU要操作的是哪一个设备呢?对于设备的选择信息又是怎么传递的呢?
那可以有两种解决方案。
方案一:在有的系统当中,这个地址线除了指明CPU要读要写的寄存器之外,有可能被用于指明这个具体的【设备编号】,但是这个设备的编号,还有这个【寄存器的编号】需要分开两次进行传输。
方案二:还有一些系统是这么处理的,我们需要连多个外设,那每一个外设都让它有一个与之对应的一组这个数据寄存器,状态寄存器和控制寄存器不就行了,所以如果有两组外设那么我们就需要设置两组这样的io端口。那两组端口就会有四个相互独立的寄存器,CPU对不同的存器进行读和写,是不是就相当于对不同的设备进行操作?所以我们可以给每个设备都设置一组对应的寄存器。当CPU要操作不同的设备的时候,就往不同的寄存器组当中进行读写数据就可以。
接口内部的一个一个的寄存器,由于接口内部会有多个端口,会有多个寄存器,那么为了标明CPU要访问的是哪一个寄存器,因此我们就需要给这些寄存器,给这些端口进行一个编址。就像给主存编址一样,CPU对于不同端口的操作是不一样的,对数据端口既有可能读也有可能写,对于控制端口只有可能写,而对于状态端口只有可能读。
接口和端口
接口内部的一个一个的寄存器,由于接口内部会有多个端口,会有多个寄存器,那么为了标明CPU要访问的是哪一个寄存器,因此我们就需要给这些寄存器,给这些端口进行一个编址。就像给主存编址一样,CPU对于不同端口的操作是不一样的,对数据端口既有可能读也有可能写,对于控制端口只有可能写,而对于状态端口只有可能读。
很多RISC精简指令集的机器当中都会采用这种统一编制的方式,因为之前我们说过精简指令集的机器会有两个访存指令:一个是LOAD,另一个是store。所以用这两个指令CPU就可以实现对所有设备的一个控制。
这里我们只是说RISC比较常用,但并不是说复杂指令集就不可以使用这种统一编制,
这种独立编制。编制由于这个地址空间是有重复的啊,比如说0~5这个地址空间,我们就没办法分辨它到底是内存还是lO设备,所以为了进行区分,我们需要设置一些专门【IO指令】。
关于什么是IO指令,我们在本章的第一个小节也介绍过。
比如英特尔的处理器就有in和out样的两个lO指令。in的意思就是说从某一个指定的io端口读入一个数据,读入到CPU的寄存器当中,这是in这个IO指令的作用,而out的作用刚好相反,就是把CPU的某一个寄存器里的内容写入到指定的lo端口当中。所以只要执行的是lo指令,那么我们就会根据地址信息去找端口,而如果不是lO指令我们就去访存,就是用这样的方式来区分主存和lO端口的地址空间。
程序查询方式
程序查询对于一些慢速的IO设备如鼠标没有什么影响。但是对于一些快速的IO设备如硬盘会大量的占用CPU进行查询
中断处理
中断处理的原理
CPU如何响应一个中断信号呢?
那首先向键盘,鼠标,打印机等等这一类的设备,或者有可能是某些时钟部件会向CPU发送一个【中断请求信号】。那我们把这种可以产生中断请求信号的部件称为【中断源】。CPU在每个指令周期的末尾都会例行的检查是否有中断请求信号需要处理,如果检测到中断请求信号,那么就需要对这个信号进行一个响应,
那首先CPU会判断当前自己的状态是否是可以响应中断的?
有的时候CPU会【不想理】这些中断请求信号,比如说执行了【关中断】,执行了关中断的指令,CPU就会暂时不理睬这些中断信号,所以首先需要判断CPU当前的状态是否处于关中断的状态,如果处于关中断的状态,那么就暂时不会响应任何中断信号,那如果此时需要响应中断信号,那么就需要进行【中断判优】,中断判优做的事情就是如果说同一时刻有好几个中断信号都需要响应,比如你的键盘敲击,还有鼠标的单击发出了两个不同的中断信号,那CPU同时接收两个中断信号的时候,就需要确定一个处理的先后顺序。因此中断判优做的就是这样的一个事情,需要判断各个中断源的优先级是怎么样的,然后CPU会优先响应优先级更高的中断源发来的一个中断信号。那经过中断判决之后就可以确定好接下来要响应的是哪一个中断请求信号,
那么刚才我们说过不同的中断请求信号所需要处理的这个过程是不一样的。就是说不同的中断信号所对应的中断服务程序肯定是不一样的,因此接下来要对这个中断进行处理的时候,首先需要通过【中断隐指令】的帮助,把CPU的指令执行流转移到正确的一个中断服务程序这儿。那本质上就是修改PC的值,让PC指向这个程序的第一条指令,然后接下来CPU就可以执行这一个中断服务程序了,那本质上也就是执行一系列的指令。中断服务程序的指令序列和我们普通程序里边使用到的指令序列也是很类似的。也是需要PC不断的加1,这样一条一条的往下执行,那这就是处理中断的一个基本流程。
关中断
【关中断】指令。
如果CPU执行了关中断的指令,就意味着接下来CPU不会响应任何一个中断请求信号,那么CPU是如何判断自己当前处于关中断的状态呢,那很简单,这个状态信息会被记录到PSW这个寄存器里边,也有【程序状态字寄存器】,那照我们给出的是8086这个很经典的芯片,它的PSW的每一位都有一个名字。有一些标志位我们之前是提过的,比如说OF、CF、SF、ZF这几个标志可以用于辅助那个【条件转移指令】的一个执行。
关中断的标志位IF:I指的是interrupt也就是中断的意思,然后f就是flag,当IF=1的时候,表示此时是开中断的一个状态,也就是说此时如果有中断请求的信号到来,那么CPU是会响应这个中断请求信号的,而如果IF=0,那么就意味着CPU此时处于关中断的状态,即便当前有中断信号到来,那么CPU也不会响应这个中断信号,还是会继续执行之前的那个程序。直到CPU再次开中断为准。
如果CPU他的的IF这一位等于零,那么就意味着它此时处于关中断的状态,那关中断这种状态的作用就是可以辅助实现某一些【原子操作】,执行了关中断指令之后,接下来即便有外部的中断信号到来,那CPU依然会继续往下执行,因为关中断就意味着CPU暂时不会理睬这些中断请求信号,接下来我们在执行一个开中断指令,那接下来再有中断请求信号的到来,CPU就可以正常的响应,而因此可以看到如果我们用关中断指令和开中断指令在他们中间夹住一段程序,那么这一段程序代码的执行就不可能被中断,一定是一气呵成的。那这就是所谓的原子操作.
非屏蔽中断
【非屏蔽】的中断
刚才我们说CPU执行关中断指令之后,任何的中断请求信号暂时都不会被响应,但是也有一些很特别的优先级很高的,这种中断信号必须被响应,这种中断信号就是【非屏蔽】的中断。比如说如果你的CPU此时处于关中断的状态,IF=0,但是你强行按住你自己的关机键,那么强行关机,这种很特别很紧急的事件是必须被响应,被处理的,在你的电脑完全断电之前,CPU需要做一些这个强制关机相关的紧急的处理。所以像这种系统掉电的情况就是必须被响应的一种特殊的中断信号,我们把称为非屏蔽终端。即便CPU此时处于关中断的状态,
那你非屏蔽中断相对应的另一个概念就是可屏蔽中断,大多数的中断请求信号都是可屏蔽中断,那当CPU处于关中断状态的时候就不会响应,可屏蔽中断。大概记住这门课当中我们更多的是在探讨外部设备发来的一些中断请求信号,而外部设备IO设备发过来的中断请求基本上都是可屏蔽中断。所以接下来如果没有特别说明,那么当我们提到所谓中断的时候,指的就是可屏蔽的中断。
中断请求标记
如果此时CPU处于开中断的状态,当它检测到一个中断请求信号,应该如何判断这个中断请求信号到底是哪一个IO设备发过来的呢?
那大家解决这个问题,我们可以设置一个【中断请求的标记寄存器】,那可以看到这些寄存器是由一个一个的【触发器】来组成的,每一个触发器可以记录一个二进制的0或者1,那么当某一个设备它所对应的这个触发器这一个比特位等于1的时候,就意味着此时有来自于这一个设备的中断请求需要被处理。
中断判优
○:代表取反
●:代表直接传输
中断隐指令
中断隐指令需要做什么?
首先第一步需要保存源程序的PC值,就是要把k+1这个值保存下来。以便于我们处理完中断之后可以恢复以前的这个程序,继续往后执行。第二点中断隐指令还需要让PC指向这个中断服务程序的第一条指令。要修改PC的值,那这些动作都是CPU检测到中断信号之后自动的会做的一系列动作。
CPU检测到某一个中断信号之后会做以下一系列的事情:
第一步。首先会关中断,那之前我们是不是说过关中段是为了实现原子操作,因为接下来保存这个程序断点这个事情是非常重要的,我们必须保证这个事情能够一气呵成,不被打断,所以执行了关中断指令之后就可以来保存这个断点,也就是要把PC当前的这个值保存下来。那通常来说pc的值可以放到堆栈里边,就是操作系统会有一个【内核堆栈区】,把PC的值放到内核堆栈里。就是比较常见的一个处理方式,那么除了用储存里的堆栈保存之外,也可以用其他的一些特定的存储单元的存储,反正我们只需要保证这个PC的值能存的进去,还能取得回来就可以了,好,那现在这个程序的运行断点保存完了之后,是不是就可以把PC的值把pc的值指向中断服务程序的第一条指令,也就需要引出中断服务程序,本质上就是在修改PC的值
硬件向量法
中断向量,它是函数的指针,而向量地址是指针的指针。
如何确定某一个中断信号所对应的中断服务程序它的起始地址呢?
那我们可以用两种方式来解决这个问题,同样的软件硬件两种解决思路,那我们重点来探讨应届了,实践思路叫【硬件向量法】,做法是这样的,首先我们是不是可以给每一个中断请求信号给他进行了编号,比如说12号中断请求,13号中断请求,14号中断请求,那么可以看到在储存里边以这些啊中断请求号所对应的主存单元里边保存了一个【jump无条件转移指令】。这个无条件转移指令指明了当前这个中断请求12号中断请求所对应的中断服务程序它的入口地址。那我们把指向这个中断服务程序起始地址的这个这个地址信息把它称为【中断向量】。好的,来看一下整体的工作过程,之前我们是说过我们可以用【硬件排队器】实现【中断判优】,那中断判优会导致只有一个中断信号所对应的输出线会输出1,然后其他的输出线一律都是0。那我们可以把之前这个排队器的输出作为【中断向量地址形成部件】这个电路的输入,然后经过这个部件的处理之后,会把所对应的某一个信号把它映射为某一个相应地址。
那这可能会有同学有疑问,既然我13号这个中断类型号,它所对的服务程序入口地址是300这个地址,那么我们为什么不把这个硬件电路直接让它输出的这个地址信息直接指向300,这样不香吗?
事实上这种方案也是可以实现的,但是大家需要知道我们把中断服务程序有可能需要被修改,比如现在打印机所对应的中断服务程序,它只占了200299这些个地址,但如果它变成了,它直接占了200399。那怎么办?那这样的话,显示器所对应的服务程序是不是只能从400这个地址开始往后存放了?所以一旦我们修改了这个中断服务程序,那么是不是就意味着我们还得再来修改这个硬件电路啊?那这显然是不科学的,好,那再回头看我们之前提出的这种两极指针的方案,虽然我们在这中断服务程序我会变长变短,可能会修改,但是系统当中可以出现的中断类型,我们是可以刚开始就规定好以后一直固定不变的,只有可能出现12号中断,13号中断,14号中断,给所有的中断类型进行一个固定的编号就可以,那如果显示器所对应的中断服务程序要从400这个地址开始存放,是不是我们只需要修改主存里边的这个【中断向量】,把以前的300把它修改了400是不是就ok了,而不需要去修改这个硬件电路,因此这就是为什么要用指针的指针这种思想来解决问题的原因。
中断服务程序
有一些事情是公共的,必须做的,【第一步】是【保护现场】。就是保护之前运行的这个程序,它的一些CPU环境。之前的这个程序执行了一系列的指令,执行到k这条指令然后就被中断了,现在就在这个中断服务程序的刚开始需要先保护现场,因为CPU内部会有很多很多寄存器,比如说acc累加寄存器还有很多通用寄存器,那么当这个程序之前的一些程序运行的过程当中,是不是会把自己运算的某一些中间结果存在这些寄存器里面?但是现在这个程序执行了一半就被中断了,那万一在这中断服务程序里边也需要修改这些寄存器里面的值,那是不是就会导致以前前边的这个程序它中间的运算结果就会丢失,对吧?好,
所以为什么要保护现场呢?就是为了让之前运行的这个程序再继续往后执行的时候,能够接着之前得到了这些中间结果继续往后运算。那通常来说要保存的现场环境就是各种各样的寄存器的值,可以把这些寄存器的值压到系统【堆栈里】,那这是中断服务程序要做的第一个事情,那么接下来【第二步】这个中断服务的一个主体那这个部分要做的事情就千差万别了,比如说键盘的输入中断信号,打印机的输出完成中断信号,要做的相应的处理肯定都是各不相同的。好,最后处理完那个中断请求之后,【第三步】就需要进行恢复现场,就是把之前运行的这个程序的acc啊,什么通用寄存器啊之类的那些寄存器的值给他恢复。也就是要从我们之前压入的这个【堆栈栈顶】弹出各种寄存器的值,把它们写回去。
对了,还记不记得之前我们说过这个堆栈的另一个作用就是原来运行的这个程序,他的PC值,【PC=K+1】。这个值也会被压到堆栈里边,对吧?然后刚才我们又说在这个堆栈的站定还会被压入什么acc啊,还有各种通用寄存器的值,压到站顶,然后这个中断服务程序处理完成之后,又需要弹出站顶的什么acc这些寄存器的值,给他恢复现场,然后就可以弹出我们之前保存的PC这个值,把PC的值赋为k+1,就可以返回到原来的这个程序继续往后执行了,它的运行环境,各种寄存器的值和之前一模一样,同时pc的值也指向了一个该有的位置。
总结
多重中断
- 【开中断】要在【保护现场和屏蔽字】【之后】执行
因为如果颠倒,那么主程序的现场可能只保留了一半,又被新的中断程序给中断掉了,这就可能导致主程序的运行现场丢失
- 【恢复现场和屏蔽字】要在【关中断】【之后】执行
恢复完现场之后才可以进行开中断
- 对于A来说,只有D的中断不可以被屏蔽,所以将D的信号设置为0
- 1表示屏蔽该中断源的请求,0表示可以正常申请
程序中断方式
引入中断机制之后,CPU和外部设备就可以并行的工作
内外中断(key:是否由当前执行的指令导致)
考研当中:中断指的是外中断。异常指的是内中断
DMA方式
DMA控制器
DMA传送过程
DMA传送方式
周期挪用:在DMA需要访存的时候,就让CPU暂停一个存取周期来让DMA访问主存
IO控制器
一个IO控制器可能要控制多个设备,所以要给每个设备接口一个地址
CPU通过控制线想IO控制器发出一个具体指令,同时在地址线上说明自己要操作哪一个设备,如果是要输出一个数据,CPU会通过数据总线把要输出的数据传送到IO控制器的数据寄存器内,之后,IO逻辑就会从数据寄存器当中取得要输出数据
CPU此时发出的IO指令可能包含一些控制的参数,这些参数保存在控制寄存器当中
为了实现对各个设备的管理,IO逻辑会给状态寄存器当中写入数据,告诉CPU当前IO设备的具体状态
IO控制方式
程序直接控制方式
要记住这个顺序
设备驱动程序和中断处理程序是直接和硬件打交道的
逻辑设备表的功能:
假脱机技术
假脱机技术可以将独占式设备改造为共享设备(比如共享打印机)
设备分配与回收
缓冲区管理
IO大题导图