计算机的四大部件
处理器(Processor):控制计算机的操作,执行数据处理功能;
主存储器(Main memory):存储程序和数据。主存中的数据会在计算机关闭后丢失;
输入/输出模块(I/O modules):用于在计算器与外部设备之间交换数据。如磁盘,打印机等;
系统总线(System bus):为处理器,主存,以及输入/输出模块之间提供通信的设施;
指令
需要执行的程序都是由一组计算机指令组成的。计算机周而复始的去存储器中提取指令,然后再执行指令,直到计算机关闭。取指令,执行指令就组成了一个基本的指令周期。
计算机将需要执行的指令地址存放在程序计数器PC(Program Counter)中,计算机根据这个指令地址从存储器中取对应的指令,将其保存在指令寄存器IR(Instruction Register)中。计算机每取一次指令,PC就会递增,指向下一次需要取得指令地址。
指令的内容包括操作和地址,假如某个计算机上的指令占据的是一个16位长的字,那么0-3位用于表示操作,剩下的4-15位就表示要操作的地址。指令的操作大致分为4类:
处理器-存储器:数据可以从处理器传送到存储器,也可以从存储器传送到处理器;
处理器-I/O:处理器和I/O模块之间可以进行数据的传送。通过处理器,数据可以输出到外部设备,也可以从外部设备输入数据;
数据处理:处理器可以执行很多算术操作和逻辑操作;
控制:控制指令的执行顺序,指令不一定按顺序执行,比如循环;
中断
中断是指正在执行指令的处理器被打断的情况,转而执行中断处理程序的情况。
中断主要分为4类:
程序中断:在某些条件下,有正在执行指令的程序产生;如算术溢出,除零异常,访问错误的位置,或者执行非法指令等;
时钟中断:由处理器的计时器产生,允许操作系统以一定的规律执行函数;
I/0中断:由I/0控制器产生,使用发送中断信号的方式通知某个操作正常完成或各种错误条件;
硬件失效中断:如断电等硬件异常产生;
为了支持对中断的处理,就需要在基本指令周期中加入一个对中断的检测步骤,即在每一个指令执行完成后都需要检测是否有中断产生,如果有就转而执行中断处理程序,否则继续执行下一个指令。
单个中断的处理:
由于中断可能在用户例程执行的任何时候产生,所以保存被中断程序的寄存器相关的值就是很必要的,目的是可以在中断程序处理完成后恢复被中断程序的执行。当中断信号产生的时候,通常会发生如下的硬件事件:
1. 设备发送中断信号给处理器;
2. 处理器检测到中断信号,先结束对当前正在执行程序的执行;
3. 处理器对中断信号进行验证,并向发出中断的设备发出确认信号,确认信号允许中断设备取消它的中断信号;
4. 处理器开始准备中断处理程序的执行。准备工作包括:将被中断程序的PSW和PC等信息保存到控制栈中;加载即将执行的中断处理程序的PC值;保存被中断程序的器处理器寄存器信息;
5. 开始中断程序的处理;
6. 中断程序处理完成后,被保存的处理器寄存器的值从栈中恢复,并装入处理器寄存器中;
7. 从栈中恢复PSW和PC的值,于是处理器就可以从被中断程序的下一个条指令继续执行;
多个中断的处理:
由于中断的产生是任意时刻的,所以就可能发生同时出现多个中断的情况。
对于多个中断的处理一般有两种方式:
1. 当处理器正在处理某个中断的时候,就不会再处理其他中断。即使此时有中断产生,该中断也必须等待处理器处理完成上一个中断。这种方式就会让所有中断按产生 时间的先后顺序依次执行;
2. 定义中断优先级,高优先级的中断会比低优先级的中断优先执行,即高优先级的中断会打算低优先级的中断的运行;
局部性原理,高速缓冲存储器
处理器在取指令和执行指令的时候会频繁的访问主存储器,但由于处理器执行速度远大于主存储器的存取速度,于是处理器执行指令的速度就会受限于主存储器的存储周期(从主存储器读取一个字或者写一个字到主存储器的时间)。为了平衡这种速度上的差异,并考虑到价格上的因素,于是就出现了高速缓冲存储器这种解决方案。
高速缓冲存储器是位于处理器和主存储器之间的一个部件。高速缓冲存储器可以采用和处理器中的寄存器一样的构造技术,因此它的存取速度远快于主存储器,这样它的存取速度就能跟上处理器的处理器周期。
高速缓冲处理器的工作原理:
高速缓冲处理器会保存一部分主存储器中数据的副本,如果处理器需要访问主存储器中的数据A的时候,它会先检查该数据A的副本是否在高速缓冲中,如果在,就直接从高速缓冲中将数据A的副本传递给处理器,如果不在,就先从主存储器中将包含数据A的固定字节数的数据读入高速缓冲中,然后再从高速缓冲中读取数据A的副本到处理器。假如主存储器一共有2n个可以寻址的字,即每个字都有一个n位的地址。我们将这些连续的字分块,每个块包含K个字,于是我们就一共有2n/K个块。高速缓冲中一个有C个槽,每个槽可以存放K个字,就相当于每个槽可以放得下一个块大小的数据,每个槽都用数据块的髙地址来标示。
高速缓冲处理器利用了局部性原理,并且很有效,其原因如下:
1. 除了分支和调用指令,程序的执行都是顺序的,而这两类指令通常只会占据一小部分。因此,大多数情况下,需要执行的下一条指令都是跟着上一条指令;
2. 很少出现很长的连续不断的过程调用序列。程序中的过程调用的深度窗口限制在一个很小的范围内,因此在较短的时间内,指令的引用局限在很少的几个过程中;
3. 大多数循环结构都有相对比较少的几个指令重复若干次组成。因此,在循环过程中,指令调用被限制在一个很小的相邻部分中;
4. 对大多数数据结构的引用都是对相邻位置的数据项进行操作;
使用高速缓冲处理器后的访问效率:
H表示在高速缓冲中找到数据的命中概率,T1表示访问高速缓冲的时间,T2表示访问主存储器的时间,那么处理器读取数据的平均时间:TS = H * T1 + (1 - H) * (T1 + T2)。
I/O操作
对I/O进行操作的三种技术:
可编程I/0
当处理器在执行程序的时候遇到一个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模块准备与处理器交换数据后,它将发送中断信号给处理器。
例子:
1. 处理器向某个I/O模块发送一个read指令,然后保存当前正在执行程序的上下文,转而执行其他程序;
2. I/O模块收到一个read指令,开始从外围设备读取数据。当数据被读入到该模块的数据寄存器,模块就通过控制总线给处理器发送一个中断信号,然后等待处理器请求该数据。当处理器发出读取数据的请求,模块就把数据放到数据总线上,然后准备下一次I/O;
3. 处理器在每个指令执行完成后,都会检查是否有中断信号;
4. 当处理器发现有来自I/O的中断,处理器保存当前正在执行的程序上下文,开始执行中断处理器程序,比如从I/O模块读取数据,保存在存储器中。然后恢复被该I/O中断的程序的上下文继续执行;
直接存储器访问(Direct Memory Access)
中断I/O消除了不必要的等待,所有它比可编程I/O高效,但是I/O模块和存储器之间的数据传送依然需要依赖处理器进行控制。这两种I/O都有两方面的缺陷:
1. I/O的传输速度受限于处理器测试设备和提供服务的速度;
2. 处理器必须执行很多指令以完成I/O的传送;
DMA提供了一种不需要通过处理器,就能直接在存储器和I/O模块中传输大量数据的方式。
当处理器需要读或写一块数据的时候,它向DMA模块发送一条命令,包括以下信息:请求是读或是写;设计的I/O设备的地址;读或写的存储器单元;读或写的字节数;然后处理器继续执行其他工作,把I/O操作直接委托给DMA模块。DMA在数据传送的时候可以直接和存储器交互,而不需要处理器的参与。当DMA完成I/O操作后,会发送一个中断信号给处理器。因此,处理器只在开始和结束阶段才参与。
但是DMA想要直接和存储器交互,需要使用总线,总线的使用存在竞争。当DMA模块在使用总线的时候,处理器如果也需要使用总线,就会暂停一个总线周期(在总线上传输一个字的时间),这样就会降低处理器的效率。不过总体说来,DMA比可编程I/O和中断I/O都要有效。