• 四. 指令系统1. 指令格式2. 扩展操作码3. 指令寻址3.1 顺序寻址3.2 跳跃寻址4. 数据寻址4.1 直接寻址4.2 间接寻址方式4.3 寄存器寻址4.4 寄存器间接寻址4.5 隐含寻址4.6 立即寻址4.7 偏移寻址基址寻址变址寻址相对寻址4.8 堆栈寻址5. 高级语言与机器级代码之间的对应5.1 x86汇编语言指令基础5.2 常用的汇编指令5.3 AT&T格式的汇编指令5.4 汇编选择语句5.5 循环语句的汇编实现5.6 函数调用汇编实现栈帧中数据的访问切换栈帧栈帧中包含的内容函数参数与返回值的传递6. CISC和RISC五. 中央处理器1. CPU的功能和基本结构1.1 运算器基本结构1.2 控制器内部基本结构2. 指令执行过程2.1 CPU处理各种指令的周期2.2 四个执行周期执行原理取址周期间址周期中断周期2.3 指令执行方案3. 数据通路3.1 CPU内部单总线方式寄存器之间的数据传送主存与寄存器之间的数据传送单总线方式例题3.2 专用数据通路4. 控制器的设计4.1 硬布线控制器设计设计思路设计方式4.2 微程序控制器的基本原理微程序控制器基本结构微指令设计4.3 微指令的编码方式直接编码方式字段直接编码字段间接编码方式微指令地址形成方式4.4 微程序控制单元的设计4.5 微程序设计分类与两种设计方式对比5. 指令流水线5.1 影响指令流水线的因素结构相关因素数据相关控制相关5.2 指令流水线的分类5.3 流水线的多发技术5.4 五段式指令流水线运算类指令LOAD指令STORE指令条件转移指令无条件转移指令6. 多处理器系统6.1 SISD、SIMD、MIMD的基本概念6.2 硬件多线程概念六. 总线1. 总线的概述2. 评价总线性能的指标3. 总线的操作和定时七. 输入输出系统1. 控制方式1.1 DMA控制方式1.2 通道控制方式1.3 系统基本组成2. 外部设备3. 接口3.1 接口工作原理3.2 接口与端口3.3 接口的类型4. 方式4.1 程序查询方式4.2 程序中断方式单中断多重中断程序中断4.3 DMA控制方式

    四. 指令系统

    即便是对于同一台计算机,所支持的指令类别也是千差万别的。各种各样的指令应该如何设定是这一章重点探讨的内容。

    指令的定义(机器指令):是指示计算机执行某种操作的命令,是计算机运行的最小功能单位。而一台计算机的所有指令的集合构成该机的指令系统,也称为指令集。

    注:一台计算机只能执行自己指令系统中的指令,不能执行其他系统的指令。如:x86架构、ARM架构。

    1. 指令格式

    一条指令就是机器语言的一个语句,它是一组有意义的二进制代码。一条指令格式通常要包括操作码字段和地址码字段两部分:

    1. 操作码(OP):想要CPU干什么。如:停机中断、求反求补、加减乘除。
    2. 地址码(A):指明这个操作对谁进行。如:不需要操作对象(停机指令)、需要操作对象(求反求补)、需要两个操作对象(运算)。

    由于各种指令所需要的操作不一样,所以地址码的数目也有可能会出现变化。所以一条指令可能包含0个、1个、2个、3个、4个地址码根据地址码数目不同,可以将指令分为零地址指令、一地址指令、二地址指令等。

    对于n位地址码的直接寻址范围=2n,若指令总长度固定不变,则地址码数量越多,寻址能力越差。

    还可以对指令进行其他分类,先来看以下概念:

    指令字长:一条指令的总长度(可能会变)

    机器字长:与CPU有关,CPU进行一次整数运算所能处理的二进制数据的位数(通常和ALU直接相关)

    存储字长:与主存有关,一个存储单元中的二进制代码位数(通常和MDR位数相同)

    可能会见到半字长指令、单字长指令、双字长指令这些术语。这指的是指令长度是机器字长的多少倍。通常情况下指令字长会影响取指令所需时间。如:机器字长=存储字长=16bit,则取一条双字长指令(32bit)需要两次访存。

    所以可以对指令按照长度进行分类:

    按照操作类型分类:

    2. 扩展操作码

    定长指令字结构+可变长操作码=扩展操作码指令格式。采用这种操作码意味着对于不同地址数的指令使用不同长度的操作码。

    举例:如果指令字长为16位,每个地址码占4位,对于三地址指令:指令字长的前4位为操作码字段OP,另外12位是三个4位长的地址字段A1,A2,A3

    三地址指令

    4位基本操作码用于三地址指令,则可以有24=16条。但至少要将1111留作扩展操作码使用,即三地址指令最多有15条。

    扩展操作码

    这么做,CPU可以在取得一条16位指令时,如果满足开头4位全1,并且58位不是全1,就可以确定这是一条二地址指令。

    同样,如果满足开头4位全1,并且58位也是全1,就可以确定这是一条一地址指令。

    接着,如果前12位都是1,就可以确定这是一条零地址指令。

    扩展操作码方法

    在设计扩展操作码指令格式时,必须注意以下两点:

    1. 不允许短码是长码的前缀,即短操作码不能与长操作码的前面部分的代码相同。
    2. 各指令的操作码一定不能重复。

    通常情况下,对使用频率较高的指令,分配较短的操作码;对使用频率较低的指令,分配较长的操作码。尽可能减少指令译码和分析的时间。如:对于二地址指令操作码是8位,三地址指令操作码是4位,二地址操作码前四位全1,所以三地址指令操作码不能出现全1

    例题:设指令字长固定为16位,试设计一套指令系统满足:

    要求格式起始指令位1指令位2/地址位指令位3/地址位指令位4/地址位
    a.有15条三地址指令 00001110A1A2A3
    b.有12条二地址指令1111111100001011A1A2
    c.有62条一地址指令11111111111100111100001101A1
    d.有32条零地址指令11111111111111111111110111100001111

    对于有15条三地址指令:其只要满足前四位不大于1110即可。

    12条二地址指令:前四位固定,并且要留八位给两个地址,所以只有4位可以当作指令,00001011可以代表12个不同二进制数即指令。

    62条一地址指令:前六位要区分指令位,所以全1,另外还要留4位做地址位,只剩6位可以用于做分配的指令位。000000111101就可以表示62不同二进制位,即指令。

    32条零地址指令:前11位区分指令位,所以全1,没有地址位,所以剩下的5位可以用来表示指令位。0000011111可以表示正好可以表示32中状态,即指令。

    这样设计好后,CPU可以根据开头几位确定是哪种地址指令。如:前11位全1,就表示这是一条零地址指令。

    上面设计方法可以得出一个结论:设地址长度为n,上一层留出m种状态,下一层可扩展出m×2n种状态。上面设计中地址长度是4位,对于第一层三地址指令设计,共有24=16种状态,留出一种状态让下一层使用。第二层设计二地址指令,由于上一层留出一种状态,所以这一层状态共有1×24=16种,这里只用12种状态,留出四种状态给下一层。第三层一地址指令设计共有4×24=64种状态,这里只用62种状态,留出两种状态给下一层。第四层设计零地址指令共有2×24=32种。

    扩展码设计

    3. 指令寻址

    指令寻址:下一条欲执行指令的指令地址。这个地址始终由程序计数器PC给出。并且有顺序寻址和跳跃寻址两种方式。

    3.1 顺序寻址

    CPU可以通过顺序寻址和跳跃寻址方式,确定下一条指令的存放地址。

    程序计数器PC可以给出下一条欲被执行的指令地址。

    顺序寻址

    上图给出一个系统,该系统采用定长指令字结构,指令字长=存储字长16Bit=2B。且主存按字编址。此时PC初始值指向0,当指令0地址内操作执行完成后,PC+1。继续执行后面,依次按顺序执行。

    PC+1

    但有的系统会采用按字节编址方式,即每条指令会占两个地址。此时PC+2

    当然有的系统也会采用变长的指令字结构:

    变长指令字结构寻址

    如上图,颜色相同的是一个指令。PC会先指向第一个指令地址0,由于CPU无法确定当前这条指令占多少个存储字,CPU会先读入第一个操作字内容,由于操作码包含在第一个字中,所以CPU可以根据操作码来判断出这条地址到底是几地址的指令。这样就可以确定这条指令占多少个字节。上面第一个行指令占4个字节,即两行,运行完之后PC会+n,即PC+4,指向4指令地址。

    变长指令字结构寻址1

    以上都是按照顺序寻址方式,这种方式PC+n就可以确定下条指令位置。这里n受定长/变长指令字结构、按字/字节编址等的影响。

    3.2 跳跃寻址

    给出一个系统,该系统采用定长指令字结构,指令字长=存储字长16Bit=2B。且主存按字编址。

    顺序寻址

    PC初始值指向0指令地址,每完成一个指令都会使PC+1。直到PC指向指令地址3,此时当执行这条指令时,同样PC+1会先执行。之后CPU知道JMP是一条无条件转移语句类似与C语言的goto语句。所以会把PC中的内容改为7,即指向7指令地址。

    跳跃寻址

    这种通过转移类指令,改变PC的值,即改变程序执行流的方式称为跳跃寻址。

    4. 数据寻址

    数据寻址:确认本条指令码的地址码指明的真实地址。

    指令是操作码+地址码。数据寻址就是地址码的解析。这个解析方式有十种:隐含寻址、立即寻址、直接寻址、间接寻址、寄存器寻址、寄存器间接寻址、相对寻址、基址寻址、变址寻址、堆栈寻址。由于有十种寻址所以只需要4位二进制标识即可。

    增加4个比特位后新的指令由操作码+寻址特征+形式地址构成。

    新的指令码

    根据中间寻址特性来确认这个形式地址应该用十种方法哪一种来解析它,得到真正的真实地址,这个真实地址叫有效地址(EA)。

    上面是对于一地址指令,二地址指令如下:

    新的二地址指令

    在接下来的介绍中,为了方便,假设指令字长=机器字长=存储字长。并且假设最终想要得到的操作数为3

    4.1 直接寻址

    直接寻址:指令字中的形式地址A就是操作数的真实地址EA,即EA=A

    直接寻址

    CPU根据指令的寻址特征知道这是直接寻址,会根据形式地址A直接找到对应主存位置中的数据。

    这种寻址访存次数:取指令访存1次,执行指令访存1次,暂不考虑存结果共访存2次。

    直接寻址优点:简单,指令执行阶段仅访问一次主存,不需专门计算操作数的地址。

    直接寻址缺点:A的位数决定了该指令操作数的寻址范围。当操作数的地址发生改变时,不易修改。

    4.2 间接寻址方式

    间接寻址:指令的地址字段给出的形式地址不是操作数的真正地址,而是操作数有效地址所在的存储单元的地址,也就是操作数地址的地址,即EA=(A)

    间接寻址

    CPU根据寻址特征知道这是间接寻址,根据形式地址A,找到主存对应的位置A,而A中保存的就是数据所在主存中的有效地址EA。即形式地址A,指向主存中的某一位置,这个位置中的地址指向就是EA

    寻址访存次数:取指令访存1次,执行指令访存2次,暂不考虑存结果共访存3次。

    同时还有两次间接寻址:

    两次间接寻址

    根据形式地址A找到主存中地址A1A1前面1标明这个地址不是有效地址EA,其指向的地址是EAEA前面的0表示这个地址指向的位置就是真是数据的位置。

    间接寻址优势:可扩大寻址范围(有效地址EA的位数大于形式地址A的位数,所以寻址范围由主存中的有效地址EA决定)。并且便于编制程序(用间接寻址可以方便地完成子程序返回)。

    缺点:指令在执行阶段要多次访存(一次间址需两次访存,多次寻址需根据存储字的最高位确定几次访存),导致寻址效率变低。

    4.3 寄存器寻址

    寄存器寻址:在指令字中直接给出操作数所在的寄存器编号,即EA=Ri,其操作数在由Ri所指的寄存器内。

    寄存器寻址

    CPU根据寻址特征知道这是寄存器寻址,所以形式地址不是指向主存中的位置,而是寄存器中的位置。CPU内部会有很多通用寄存器,根据形式地址Ri可以找到寄存器编号。

    寻址访存次数:取指令访存1次,执行指令访存0次,暂不考虑存结果共访存1次。

    寄存器寻址优点:指令在执行阶段不访问主存,只访问寄存器,由于CPU中寄存器不会太多,所以指令字短且执行速度快,支持向量/矩阵运算。

    寄存器寻址缺点:寄存器价格昂贵,计算机中寄存器个数有限。

    4.4 寄存器间接寻址

    寄存器间接寻址:寄存器R中给出的不是一个操作数,而是操作数所在主存单元的地址,即EA=(Ri)

    寄存器间接寻址

    CPU根据寻址特征知道这是寄存器间接寻址,根据形式地址指明的寄存器编号,而这个寄存器编号中的内容才是有效地址EA,其指向主存中的某一位置。

    寻址访存次数:取指令访存1次,执行指令访存1次,暂不考虑存结果共访存2次。

    寄存器间接寻址特点:与一般间接寻址相比速度更快,但指令的执行阶段需要访问主存(因为操作数在主存中)。

    4.5 隐含寻址

    隐含寻址:不是明显地给出操作数的地址,而是在指令中隐含着操作数的地址。

    隐含寻址

    有的地址显示给出的地址只是指明,其中一个操作数的位置,而另一个操作数会默认在ACC累加寄存器中,但是这个操作数并没有在指令中显示的给出,所以这是隐含寻址。

    优点:有利于缩短指令字长。

    缺点:需增加存储操作数或隐含地址的硬件。

    4.6 立即寻址

    立即寻址:形式地址A就是操作数本身,又称为立即数,一般采用补码形 式。寻址特征位#表示立即寻址特征。

    寻址访存次数:取指令访存1次,执行指令访存0次,暂不考虑存结果共访存1次。

    立即寻址优点:指令执行阶段不访问主存,指令执行时间最短。

    立即寻址缺点:A的位数限制了立即数的范围。如A的位数为n,且立即数采用补码时,可表示的数据范围为2n12n11

    六种寻址方式总结:

    六种寻址方式总结

    4.7 偏移寻址

    以某个地址作为起点,形式地址视为偏移量。偏移寻址有三种:相对寻址、基址寻址和变址寻址。

    偏移寻址

    上图最左边JMP会让程序跳转到第7行。中间的JMP指令会让程序以当前程序的起始位置100,往后偏移7位,即107。最右边JMP指令,会以当前程序执行行的位置为起始位置103,往后偏移3位到107

    这三种偏移方式区别在于偏移的起点不一样。

    1. 基址寻址:以程序的起始存放地址作为"起点"。
    2. 变址寻址:程序员自己决定从哪里作为"起点"。
    3. 相对寻址:以程序计数器PC所指地址作为"起点"。

    基址寻址

    基址寻址:将CPU中基址寄存器(BR)的内容加上指令格式中的形式地址A,而形成操作数的有效地址,即EA=(BR)+A

    有的计算机会带有基址寄存器:

    基址寻址

    采用这种基址寄存器,则指令中还有形式地址A,基址寄存器BR会指向当前程序的起始位置。最终的有效位置,只需要用基址寄存器中存放的地址加上形式地址A(偏移量)就可以得到最终的有效地址EA。即将ABR中存放的地址送往算术逻辑单元ALU进行一个加法运算就可以得到EA

    注:可对比操作系统OS课中的"重定位寄存器"就是"基址寄存器"。

    而有的计算机内部不会有专门的基地址寄存器,而是使用某个通用寄存器。

    基址寻址(无基址寄存器)

    CPU根据寻址特征知道这是基址寻址,另外还需要花几个比特位指明基地址存放在通用寄存器哪个位置。上图指明存放在通用寄存器R0位置。之后和之前一样,取出通用寄存器R0地址和A地址送到ALU算术逻辑单元种进行相加得到EA

    其中R0要根据通用寄存器个数判断占多少位。如果通用寄存器有8个存储空间,那么R0就需要3位,即可。因为23=8能表示所有情况。

    优点:可扩大寻址范围(基址寄存器的位数大于形式地址A的位数);用户不必考虑自己的程序存于主存的哪一空间区域,故有利于多道程序设计,以及可用于编制浮动程序便于程序"浮动",可以从内存当中任何一个地址作为程序起始地址,方便实现多道程序并发运行。

    注:基址寄存器是面向操作系统的,其内容由操作系统或管理程序确定。在程序执行过程中,基址寄存器的内容不变(作为基地址),形式地址可变(作为偏移量)。当采用通用寄存器作为基址寄存器时,可由用户使用汇编语言决定哪个寄存器作为基址寄存器,但其内容仍由操作系统确定。

    变址寻址

    变址寻址:有效地址EA等于指令字中的形式地址A与变址寄存器IX的内容相加之和,即EA=(IX)+A,其中IX可为变址寄存器(专用),也可用通用寄存器作为变址寄存器

    如果计算机中有变址寄存器IX

    变址寄存器IX

    采用这种基址寄存器,则指令中还有形式地址A,变址寄存器IX会指向当前程序的起始位置。最终的有效位置,只需要用变址寄存器中存放的地址加上形式地址A(偏移量)就可以得到最终的有效地址EA。即将AIX中存放的地址送往算术逻辑单元ALU进行一个加法运算就可以得到EA

    可以发现变址寻址和基址寻址方式一样。他们的区别在于,变址寄存器是面向用户的,在程序执行过程中,变址寄存器的内容可由用户改变。另外IX作为偏移量,形式地址A不变作为基地址,和基址寻址相反。

    变址寻址原理:先给出一段程序

    该程序存储结构如下:

    变址寻址原理

    从上面可以体会到,A作为基址,而IX作为偏移量即代码中对应的i。不断改变变址寄存器IX的内容,便可很容易形成数组中任一数据的地址,特别适合编制循环程序。

    变址寻址优点:在数组处理过程中,可设定A为数组的首地址,不断改变变址寄存器IX的内容,便可很容易形成数组中任一数据的地址,特别适合编制循环程序。

    复合寻址:

    可以采用基址+变址复合方式寻址。

    如果一个程序在主存中随机存放,就需要一个基地址指向程序的起始位置。此时EA=(IX)+((BR)+A)

    注:实际应用中往往需要多种寻址方式复合使用(可理解为复合函数)

    相对寻址

    相对寻址:把程序计数器PC的内容加上指令格式中的形式地址A而形成操作数的有效地址,即EA=(PC)+A,其中A是相对于PC所指地址的位移量,可正可负,补码表示。

    相对寻址

    先从主存地址1000地方取出指令,当取出指令后CPU会让PC+1,若当前指令字长为2B,则PC+2。因此取出当前指令后PC的值为1002。那么此时CPU根据寻址特征知道这是相对寻址,所以EA的值就是当前PC的值再加上形式地址A的值。如果A值是负,则从当前PC所指行往前偏移,如果是正,则往后偏移。

    相对寻址原理:

    相对寻址原理

    当执行到M+3主存行地址指令时,如果还按照之前的方式跳转,会跳转到2主存行地址,这一行是其他代码显然错误。为了解决这个问题采用相对寻址方式,当执行M+3主存行指令时,PC+1指向M+4,这里修改地址码值为-4(补码表示),此时PC=M+44=M,所以以后不管这段代码在哪个位置,采用相对寻址方式都会指向M主存行位置。

    相对寻址原理1

    同时还能发现一个问题,当程序代码移动时,数组a[0]可能不再存放在7主存行位置,所以要修改M行地址码值,使其与a[0]所在主存位置对应,显然每次都要修改很麻烦。所以现实中都是采用分段方式解决:即程序段(只存放指令代码)和数据段(只存放数据)分开存放。

    采用相对寻址优点:操作数的地址不是固定的,它随着PC值的变化而变化,并且与指令地址之间总是相差一个固定值,因此便于程序浮动(一段代码在程序内部的浮动)。相对寻址广泛应用于转移指令。

    注意:基址寻址中的浮动指的是整段程序在内存中的浮动。而相对寻址的浮动指的是一段代码在程序内部的浮动。

    三种寻址方式总结:

    三种寻址方式总结

    注意:取出当前指令后,PC会指向下一条指令,相对寻址是相对于下一条指令的偏移

    4.8 堆栈寻址

    堆栈寻址:操作数存放在堆栈中,隐含使用堆栈指针(SP)作为操作数地址。这个堆栈指针存放在寄存器SP当中。

    堆栈是存储器(或专用寄存器组)中一块特定的按后进先出(LIFO)原则管理的存储区,该存储区中被读/写单元的地址是用一个特定的寄存器给出的,该寄存器称为堆栈指针(SP)。

    这个堆栈可以用两种方式实现:一种是采用专门寄存器存放专门元素。另一种方式是在主存中划出一片区域用作堆栈。

    用寄存器实现堆栈原理:

    堆栈寻址

    这里用四个寄存器实现堆栈,系统中会用专门的寄存器SP来指向当前栈顶元素的位置。当前SPR0。由于这里只有四个寄存器,所以SP只需要用两位就可以表示所有的值。

    假设现在要用堆栈里的两个栈顶元素来完成一次加法操作。加数和被加数会先放到ACCX中。通过ALU计算出结果。具体操作是,用汇编指令POP弹出栈顶元素,并将其放入ACC累加寄存器中。弹出后将SP+1指向弹出后栈顶的元素即R1。同样用POP指令弹出栈顶元素放入X中。接着SP+1指向R2。现在加数和被加数已经有了,之后用汇编语句ADD将两个数相加的结果放入Y中。最后通过汇编指令PUSH将结果Y压入栈顶,这个压栈具体做法是,将SP1指向R1。然后再将Y的值放入SP所指向的R1寄存器中。

    汇编指令如下:

    堆栈寻址汇编语句

    上面情况是栈顶在小地址方向,还有的情况是栈顶在大地址方向。栈顶大地址方向的汇编指令:

    堆栈寻址汇编语句2

    上面通过几个寄存器实现的堆栈称为硬堆栈。还有一种方式是软堆栈,即从主存中划出一片区域当堆栈。这种方式通过POP和PUSH对栈进行操作都会进行一次访存,而硬堆栈由于存放在寄存器中所以不用进行访存。

    软堆栈

    显然采用寄存器实现的硬堆栈速度更快,但成本高;而软堆栈访问速度慢,但成本更低。在实际的系统中通常采用软堆栈实现。堆栈可用于函数调用时保存当前函数的相关信息。

    十种寻址方式总结:

    十种寻址方式总结

    5. 高级语言与机器级代码之间的对应

    机器语言与汇编语言都是机器级代码。考试只考x86汇编语言,如果考察其他汇编语言题中会给出详细注释。

    5.1 x86汇编语言指令基础

    指令作用:要么处理数据,要么改变程序执行流。指令的格式:操作码+地址码,操作码指出数据怎么处理,地址码指明了数据存放在哪。而数据可以存放在寄存器中,主存里,指令里。如果是在寄存器中,指令给出寄存器名即可。如果是在主存中,指令给出主存地址即可,同时要指明读写长度。如果在指令中就是立即寻址。

    mov指令为例:

    语法格式功能
    mov 目的操作数d,源操作数s将源操作数s复制到目的操作数d所指的位置

    上面中括号表示主存地址。

    如何指明内存的读写长度:dword ptr:双字(32bit);word ptr:单字(16bit);byte ptr:字节(8bit)

    x86架构的CPU,寄存器如下:寄存器E=Extended=32bit,所以寄存器都是以e开头。

    x86架构寄存器

    前四个为一组用于存什么数据未知,所以称为通用寄存器。

    中间两组ESI,EDI是变址寄存器。变址寄存器可用于线性表、字符串的处理。

    最后两个寄存器EBP,ESP分别指明堆栈的基指针和顶指针。主要用于实现函数的调用。

    前四个寄存器使用较为灵活,可以去掉前面的E,使用低地址的16bit。即ax代表使用EAX寄存器的低地址16bit

    寄存器低地址使用

    并且可以指定使用8bit,如:ah表示EAX寄存器中的8bit

    寄存器低地址使用2

    当然最常用的还是直接使用32bit

    在看几个常见操作:

    5.2 常用的汇编指令

    x86常见的算术运算指令:

    功能汇编指令解释
    add d,s计算d+s,结果存入d
    sub d,s计算ds,结果存入d
    mul d,s
    imul d,s
    无符号数ds,乘积存入d
    有符号数ds,乘积存入d
    div s
    idiv s
    无符号数除法edx:eax/s, 商存入eax, 余数存入edx
    有符号数除法edx:eax/s, 商存入eax, 余数存入edx
    取负数neg dd取负数,结果存入d
    自增inc dd++, 结果存入d
    自减dec dd,结果存入d

    上面指令后的操作数可能来自寄存器、主存和指令这三个地方。而为了提高运行效率减少主存访问,在x86汇编指令中两个操作数不能同时来自主存。由于最终处理的结果要放回到d中,所以d不可能是常量,只可能是寄存器或者主存地址。

    注意除法指令,divs这里的s是除数,而被除数会被提前放在edxeax寄存器中。而edx:eax指的是在进行除法运算之前,需要对被除数进行位扩展,如:32bit32bit,此时被除数需要扩展到64bit,即64bit32bit。而一个寄存器只有32bit,所以需要两个寄存器存放,edx存放高32位,eax存放低32位。

    通常会用<reg>代表寄存器、<mem>代表内存、<con>代表常数。

    x86常见的逻辑指令

    功能汇编指令解释
    and d,sds逐位相与,结果放回d
    or d,sds逐位相或,结果放回d
    not dd逐位取反,结果放回d
    异或xor d,sds逐位异或,结果放回d
    左移shl d,sd逻辑左移s位,结果放回d(通常s是常量)
    右移shr d,sd逻辑右移s位,结果放回d (通常s是常量)

    其他指令:

    用于实现分支结构、循环结构的指令:cmp、test、jmp、jxxx

    用于实现函数调用的指令:push、pop、call、ret

    用于实现数据转移的指令:mov

    5.3 AT&T格式的汇编指令

    AT&T格式常用于Unix和Linux。intel格式常用于Windows。

    AT&T常用格式:

    功能汇编指令解释对应intel格式
    目的操作数d、源操作数sop s,d源操作数在做,目的操作数在右op d,s
    寄存器表示mov %ebx,%eax寄存器名前必须加"%"mov eax,ebx
    立即数的表示mov $985,%eax立即数之前必须加"$"mov eax,985
    主存地址的表示mov %eax,(af996h)主存地址用小括号表示mov [af996h],eax
    读写长度的表示movb $5,(af996h)
    movw $5,(af996h)
    movl $5,(af996h)
    addl $5,(af996h)
    指令后加b,w,l分别表示读写
    长度byte、word、dword
    mov byte ptr [af996h],5
    mov word ptr [af996h],5
    mov dword ptr [af996h],5
    add byte ptr [af996h],4
    主存地址偏移量的表示movl -8(%ebx),%eax
    movl 4(%ebx,%ecx,32),%eax
    偏移量(基址)mov eax,[ebx-8]
    mov eax,[ebx+ecx*32+4]

    对于最后mov eax,[ebx+ecx*32+4],做一下详细解释:

    偏移量复杂例子

    对于上图,这是一个结构体数组。要访问数据元素3中的变量1,需要知道这个结构体数组基址,然后+。这里的变址是要访问的索引号,比例因子就是每个数组大小,这里是32bit,最后再加上变量04B就是变量1的位置。即ebx+332+4

    5.4 汇编选择语句

    前面已经介绍基本汇编语句,这里会介绍选择语句的汇编方式。

    指令存储在主存中,每次取出一条指令PC会自动+1,指向下一条指令。但是选择语句可能会改变程序的执行流。注意在x86处理器中程序计数器PC通常称为IP

    改变程序执行流需要用到无条件转义指令:JMP

    指令名语法功能
    jmpjmp <地址>PC无条件转移至地址处

    这里的<地址>可以是常数、寄存器、主存。但最常用还是"标号"锚定:

    当执行到jmp NEXT时,程序计数器PC会跳转到最后一行,即NEXT标记的位置。这里的标号不一定是NEXT,可以自定义名字。

    JMP指令类似于C语言的goto语句,虽然能实现跳转,但无法实现if...else..语句。要实现选择语句需要用到条件转移指令jxxx

    常用的jxxx语句及功能:

    语句语法功能
    jeje <地址>a==b则跳转
    jnejne <地址>a!=b则跳转
    jgjg <地址>a>b则跳转
    jgejge <地址>a>=b则跳转
    jljl <地址>a<b则跳转
    jlejle <地址>a<=b则跳转

    上面指令通常要搭配CMP指令,CMP指令用于比较两个数。

    语法功能
    cmp a,b比较ab的值,a,b可能是常量、主存地址或寄存器

    例1:

    例2:将下面C语言转换为汇编语言

    汇编语言:

    扩展:CMP指令的底层原理。

    运算标志位

    之前学习过,每次ALU运算都会产生新的标志位覆盖上次标志位:

    而跳转指令JMP之前会使用CMP指令,这个指令本质是将做一次ab的运算,这个运算会产生上面几个标志位。这些标志位,会存放到PSW程序状态寄存器中,intel称其为标志寄存器。

    标志寄存器

    jne这条指令在a!=b时发生跳转,CPU在执行这条指令时,会读取之前CMP产生的标志位ZF是否等于0,如果等于0满足条件进行跳转。其他指令也可以从标志位中得出跳转信息:

    5.5 循环语句的汇编实现

    可以用条件转移指令实现循环。有以下C语言代码:

    转换为汇编语言:

    所以用条件转移指令实现循环,需要4个部分构成:

    1. 循环前初始化
    2. 是否直接跳出循环
    3. 进入循环主体
    4. 是否继续循环

    除了用条件转移指令实现,还可以用LOOP指令。

    指令语法功能
    loop 循环体名循环计数器,并且若不等于0,跳转到循环体

    实现:有以下一段C语言

    使用LOOP指令实现循环:

    上面汇编代码可以知道LOOP指令相当于:

    注意:ecx可以作为循环计数器,其寄存器不能,所以这里必须用ecx寄存器。

    理论上能用loop指令实现的功能一定能用条件转移指令实现。而使用loop指令可能会使代码更清晰简洁。

    补充:loop指令还有loopx指令。如loopnz,和loopz。其中loopnz是当ecx!=0&&ZF==0时,继续循环。而loopz是当ecx!=0&&ZF==1时,继续循环。

    5.6 函数调用汇编实现

    高级语言在执行函数如main()函数时,会先将其压入函数调用栈,这个压入的函数称为栈帧。如果main()函数调用其他函数时,仍会将被调用函数压入函数栈中,称为栈帧。

    每个函数的栈帧中包含函数达阔内定义的局部变量和保存函数调用的信息。

    高级语言函数调用栈帧

    其中caller()add()函数代码如下:

    对应的汇编代码如下:

    所以可以知道函数调用指令是:call 函数名。函数返回指令是:ret

    其调用执行原理本质就是CPU中程序计数器,指向改变过程。当产生函数调用时,就是让PC寄存器指向被调用函数的位置。同样ret指令也是让PC寄存器指向位置发生改变。在x86中通常称PCIP

    CALL指令作用:

    RET指令作用:从函数的栈帧顶部找到IP旧值,将其出栈并恢复IP寄存器。

    具体执行是:call指令执行时,首先会将IP寄存器指向的值压入栈中保存,之后再将IP指向被调用起始位置。当被调用函数执行完后,ret指令会从栈顶位置取出刚刚IP指向的旧地址,将这个值写回IP寄存器。这一就完成函数调用。

    栈帧中数据的访问

    之前看到的函数调用栈实际在内存中是倒过来存放的。

    函数调用栈倒置

    这是因为在内存中,栈底对应的是内存的高地址,栈顶对应的是低地址。

    函数调用栈子啊内存中位置

    之前学过x86中的寄存器,其中EBP和ESP寄存器分别用于存储堆栈基指针和堆栈顶指针。并且在一个CPU内部只有一个EBP和ESP。

    访问栈帧中的数据需要用到push和pop指令。push、pop指令实现入栈、出栈操作。x86默认以4字节为单位。指令格式如下:

    指令语法功能注意事项
    push a先让ESP减4,再将a压入栈中a可以是立即数、寄存器或主存地址
    pop b栈顶元素写入b,再让ESP加4b可以是寄存器、主存地址

    例子:

    假设当前eax寄存器中的值是211。内存结构如下(黄色部分是一个函数esp指向栈顶,ebp指向栈底):

    push和pop指令原理

    push eax会先让esp值4,即向下移动四个字节,让后将eax中的值放入esp指向的位置,即栈顶。

    push和pop指令原理1

    push 985同样先让esp值4,即向下移动四个字节,让后将立即数985值放入esp指向的位置,即栈顶。

    push和pop指令原理2

    push [ebp+8],会先让ebp+8,esp4,然后将此处的值666放入栈顶。

    push和pop指令原理3

    pop eax会让esp所指位置的值放入eax中,再让esp+4

    push和pop指令原理4

    之后的指令执行原理同上。

    通过上面例子可以发现push和pop只能对栈顶元素进行操作,这样访问就有限制,还有更灵活的方法mov指令。

    可以使用加法指令和减法指令来对esp和edp两个指针进行移动。

    例子:

    其内存中的结构如下:

    mov指令

    sub esp,12这条指令会让esp指针向下移动三位。

    mov指令1

    之后执行原理类似。

    因此可以用mov指令,结合esp、ebp指针访问栈帧数据可以用减法/加法指令,即sub/add修改栈顶指针esp的值。

    切换栈帧

    当发生函数调用时,需要修改ebp和esp指向,让其指向新的函数顶部和底部。这个切换过程原理如下:

    总结:

    函数切换栈帧总结

    每个被调用函数在执行前都会有enter部分,最后都会有leave部分。

    栈帧中包含的内容

    当前有一段代码

    假设当前运行的是caller()函数,根据之前内容,可以知道栈帧中通常包含以下内容:

    所以一个函数栈内容分布如下:

    函数栈帧

    可以看到中间有空闲未使用区域。这是正常现象因为当使用gcc编译器时,编译器会将每个栈帧大小设置为16B的整数倍(当前函数的栈帧除外),因此栈帧内可能出现空闲未使用的区域。

    栈帧内容总结:

    栈帧内容总结

    函数参数与返回值的传递

    通过上面学习可以知道函数参数通过edp向上移动可以获取。

    有以下一段汇编代码

    执行完这段汇编程序后,函数栈如下:

    汇编实战

    之后会执行call add指令,add函数汇编指令如下:

    执行完mov ebp,esp指令后栈帧如下:

    汇编实战2

    之后mov eax,[ebp+12]mov edx,[ebp+8],分别可以访问到y,x的值。并将这两个值放入eax,edxadd eax,edx会将这两个变量相加,相加后的结果再放回eax中。

    汇编实战3

    最后执行leave指令切换上一层函数栈帧,再执行ret指令让程序回到函数调用后的一行继续执行。

    可以看到add函数将返回值写到eax寄存器中。所以caller函数中的mov [ebp-4],eax就是取返回值的操作。即对应C语言中的sum=add(temp1,temp2)操作。之后仍会把sum放入eax寄存器,让上一层函数取返回值,即mov eax [ebp-4]。由于C语言的返回值只有一个,所以通常会把返回值写入eax中。这样上一层函数直接去eax中取出返回值即可。

    至此对函数调用机器级语言进行总结:

    汇编实战总结

    最后还有一个问题,当调用者某些值已经存在eax寄存器中,那么调用发生时,被调用者也有可能用到eax寄存器,从而会覆盖其中的值。解决方法是在函数调用之前对寄存器eax中的值进行压栈保存即可。等函数返回后再将这些值从栈中恢复到寄存器即可。所以函数栈中还可能有一层是保存部分寄存器的值。

    函数调用栈中寄存器的值

    6. CISC和RISC

    CISC和RISC是指令设计的两个方向。

    CISC(复杂指令集计算机系统):设计思路是一条指令完成一个复杂的基本功能。代表:x86架构,主要用于笔记本、台式机等。

    RISC(精简指令集计算机系统):设计思路是一条指令完成一个基本动作,多条指令组合完成一个复杂的基本功能。代表:ARM架构、手机、平板等。

    可以理解为RISC相当于C语言基本语法,而CISC相当关于提供库函数的C语言。再后来的开发中发现典型程序中80%的语句仅仅使用处理器中的20%的复杂指令。

    比如设计一套能实现整数、矩阵加//乘运算的指令集:

    CISC和RISC对比

    对比项目CISCRISC
    指令系统复杂、庞大、丰富简单、精简
    指令数目一般大于200一般小于100
    指令字长不固定定长
    可访存指令不加限制只有Load/Store指令可以访存
    各种指令执行时间相差较大绝大多数在一个周期内完成
    各种指令使用频度相差很大都比较常用
    通用寄存器数量较少
    目标代码难以用优化编译生成高效的目标代码程序采用优化的编译程序,生成代码较为高效
    控制方式绝大多数为微程序控制绝大多数为组合逻辑控制(效率更高)
    指令流水线可以通过一定方式实现必须实现

    五. 中央处理器

    本章会基于之前的学习进行补充和完善。

    CPU基本构成是:ALU(第二章已学)、寄存器(第三章已学)、中断系统(最后一章)、CU控制单元(本章)。

    1. CPU的功能和基本结构

    CPU需要实现以下功能:

    1. 指令控制。完成取指令、分析指令和执行指令的操作,即程序的顺序控制。

    2. 操作控制。一条指令的功能往往是由若干操作信号的组合来实现的。CPU管理并产生由内存取出的每条指令的操作信号,把各种操作信号送往相应的部件,从而控制这些部件按指令的要求进行动作。

    3. 时间控制。对各种操作加以时间上的控制。时间控制要为每条指令按时间顺序提供应有的控制信号。

    4. 数据加工。对数据进行算术和逻辑运算。

    5. 中断处理。对计算机运行过程中出现的异常情况和特殊请求进行处理。

      正常情况下CPU会顺序执行程序,但计算机内会有一些突发的状况(如鼠标单击其他软件),因此需要这种中断处理。当CPU检测到特殊的中断信号后,会转而处理中断程序的一系列指令代码,当中断执行完后再回去执行原本的程序指令。

    CPU结构如下:

    CPU结构

    从运算器和控制器角度对CPU功能进行分类:

    运算器会对程序进行加工操作。

    控制器:协调并控制计算机各部件执行程序的指令序列,基本功能包括取指令、分析指令、执行指令

    接下来会详细探讨运算器和控制器基本结构。

    1.1 运算器基本结构

    上面介绍过运算器由两部分构成:算术逻辑单元和通用寄存器组。

    算术逻辑单元:主要功能是进行算术/逻辑运算。

    通用寄存器组:如AX、BX、CX、DX、SP等,用于存放操作数(包括源操作数、目的操作数及中间结果)和各种地址信息等。其中SP是堆栈指针,用于指示栈顶的地址。

    通用寄存器组

    右图中AH,AL指的是AX寄存器的高位和低位。通用寄存器中保存的数据都有可能成为ALU的输入,由于ALU有两个输入口,所以每个寄存器要提供两个连线,这里的两根连线是泛指,如果一个寄存器16bit,那每一边都需要16根连线总共32根连线连接ALU。

    ALU连线通路

    上面这种连线方式称为专用数据通路:根据指令执行过程中的数据和地址的流动方向安排连接线路。显然这种连接方式由于寄存器数目增加连接线路也会越来越多,所以制造成本会提高。

    所以专用数据通路优势:性能较高,基本不存在数据冲突现象,但结构复杂,硬件量大,不易实现。

    同时还会存在另一个问题:如果直接用导线连接,相当于多个寄存器同时并且一直向ALU传输数据,显然ALU只需要A,B只需要两个寄存器提供数据就可以。解决这种问题方法:

    上面是专用数据通路实现方式,还有另一种连接方式:CPU内部单总线方式

    CPU内部单总线方式:将所有寄存器的输入端和输出端都连接到一条公共的通路上。

    CPU内部单总线方式

    假如现在要把R0数据复制到R2中,在R2的输入端R2in一个高电平,代表R2输入通路被打通。这样R0数据通过数据总线流入R2寄存器中。

    这种内部单总线方式结构简单,容易实现,但数据传输存在较多冲突的现象,性能较低。

    冲突现象解释:如果现在用ADD指令R0,R2两个数据相加,这两个寄存器中的数据通过数据总线流入ALU,由于两个寄存器数据都通过一条总线,所以产生数据冲突问题。解决方法是在ALU其中一个输入端增加暂存寄存器。

    暂存寄存器

    这样的话就可以先把R0数据输送到总线上,这样R0数据会先放入暂存寄存器中,之后撤销R0的有效信号,R0对应的三态门信号失效。之后让R2所在的总线导通,R2会通过另一条总线输入到B端口。最后运算的结果通过ALU输出端口输送到数据总线上,最后存放在R0寄存器中。

    运算器内部结构

    由于B端口输入的电信号可能不稳定,而不稳定信号也会被ALU通过数据总线放回R0。所以还需要在ALU输出端再加入一个暂存寄存器。这样计算结果会先放入暂存寄存器,等信号稳定后,再让暂存寄存器上边的三态门导通,从而将结果通过数据总线放入R0中。

    运算器内部完整结构

    同时为了方便某些复杂运算的实现,ALU输出端的暂存寄存器还可以增加一些。如:移位功能变为移位寄存器,累加功能变为累加寄存器。不过最常用的做法是在数据总线上多增加一个ACC累加寄存器。

    运算器内部完整结构1

    除了以上结构,在寄存器端还会增加一个PSW标志寄存器,作用是保留由算术逻辑运算指令或测试指令的结果而建立的各种状态信息,如溢出标志(OP)、符号标志(SF) 、零标志(ZF) 、进位标志(CF)等。PSW中的这些标志位参与并决定微操作的形成。

    运算器内部完整结构2

    除了以上寄存器之外还需要有移位器,对运算结果进行移位操作。如二进制乘法就是加法操作+移位操作。因此ALU输出端寄存器通常用作移位使用。

    移位寄存器

    最后运算器内部还需要提供计数器,用于控制乘除运算的操作步数。

    所以运算器内部结构总结如下:

    1. 算术逻辑单元:主要功能是进行算术/逻辑运算。
    2. 通用寄存器组:如AX、BX、CX、DX、SP等,用于存放操作数(包括源操作数、目的操作数及中间结果)和各种地址信息等。SP是堆栈指针,用于指示栈顶的地址。
    3. 暂存寄存器:用于暂存从主存读来的数据,这个数据不能存放在通用寄存器中,否则会破坏其原有内容。
    4. 累加寄存器:它是一个通用寄存器,用于暂时存放ALU运算的结果信息,用于实现加法运算。
    5. 程序状态字寄存器:保留由算术逻辑运算指令或测试指令的结果而建立的各种状态信息。如:溢出标志(OP)、符号标志(SF)、零标志(ZF) 、进位标志(CF)等。PSW中的这些位参与并决定微操作的形成。
    6. 移位器:对运算结果进行移位运算。
    7. 计数器:控制乘除运算的操作步数。

    移位寄存器

    1.2 控制器内部基本结构

    控制器内部总结构:

    1. 程序计数器:用于指出下一-条指令在主存中的存放地址。CPU就是根据PC的内容去主存中取指令的。因程序中指令(通常)是顺序执行的,所以PC有自增功能。
    2. 指令寄存器:用于保存当前正在执行的那条指令。
    3. 指令译码器:仅对操作码字段进行译码,向控制器提供特定的操作信号。
    4. 微操作信号发生器:根据IR的内容(指令)、PSW的内容(状态信息)及时序信号,产生控制整个计算机系统所需的各种控制信号,其结构有组合逻辑型和存储逻辑型两种。
    5. 时序系统:用于产生各种时序信号,它们都是由统,一时钟(CLOCK)分频得到。
    6. 存储器地址寄存器:用于存放所要访问的主存单元的地址。
    7. 存储器数据寄存器:用于存放向主存写入的信息或从主存中读出的信息。

    第一个重要部件PC,其有自增功能,而有的计算机是送给ALU实现自增的。

    控制器基本结构

    之后取出一条指令后会把这个指令放入指令寄存器IR当中。一个指令由操作码和地址码构成,地址码可以有多个。地址码指明了操作数的存放地址。所以地址码会输送到内部总线上,而操作码部分会送给控制单元。

    控制器基本结构1

    首先这个指令码会送给指令译码器,输入后这个译码器根据操作会将某一段打通。根据译码器输出信号就可以决定接下来是哪些微操作。所以译码器的输出信号会作为微操作信号发生器的输入信号,用来判断该指令对应的微操作序列应该是什么。

    控制器基本结构2

    由于这些微操作序列执行需要一个先后次序。因此还需要一个时序系统,用于产生时序信号。微操作信号发生器每接受到一个节拍信号就会执行下一个微操作,会发出下一个微操作对应的信号。除了指令信号还需要根据PSW标志信息决定接下来的微操作。

    控制器基本结构3

    最后还需要存储器地址寄存器(MAR),指令的地址码通过给AdIrout一个有效的信号打通内部总线,同时给MARin一个有效信号,这样这个地址信息会输入到寄存器MAR当中。之后MAR会将地址信息通过地址总线传送给主存,主存根据信号地址取出数据放回MDR中。

    控制器基本结构4

    上面MDR的MDRinE指的是从外部数据总线输入数据的通路是否有效。而MDRin指的是从CPU内部的总线输入数据通路是否有效。

    控制器基本结构5

    CPU内部完整结构总结:

    CPU内部完整结构

    上面橙色寄存器是可用于编程的,灰色是不可以编程使用的。

    2. 指令执行过程

    指令周期:CPU从主存中每取出并执行一条指令所需的全部时间。

    指令周期

    一个指令周期可以被划分为:取值周期和执行周期两个部分。

    指令周期常常用若干机器周期来表示,机器周期又叫CPU周期。一个机器周期又包含若干时钟周期(也称为节拍、T周期或CPU时钟周期,它是CPU操作的最基本单位)。

    定长时钟周期

    上图三个周期所需要的时钟周期都为4(T0,T1,T2,T3,T4)。所以被称为定长机器周期。但事实上对于取指令和执行指令时间很大概率是各不相同的,时间和访问主存有关,通常情况下都是不定长的机器周期。

    不定长机器周期

    2.1 CPU处理各种指令的周期

    每个指令周期内机器周期数可以不等,每个机器周期内的节拍数也可以不等。看下边几个例子可以加深对这句话理解。

    指令周期执行流程:

    指令周期执行流程

    CPU可以通过触发器判断现在位于哪个周期。上面四个周期可以设置四个触发器。

    周期触发器

    一个触发器可以存放1个二进制位。如果处于取值周期,会把FE取值1,剩下取值都是0。之后在哪一个周期,这个周期的触发器就设置为1,其余为0

    四个工作周期都有CPU访存操作,只是访存的目的不同。取指周期是为了取指令,间址周期是为了取有效地址,执行周期是为了取操作数,中断周期是为了保存程序断点。

    2.2 四个执行周期执行原理

    上面介绍了CPU四个执行周期:取址周期、间址周期,执行周期和中断周期。

    取址周期

    这个周期执行流程有以下几个阶段:

    1. 当前指令地址送至存储器地址寄存器,记做:(PC)MAR
    2. CU发出控制信号,经控制总线传到主存,这里是读信号,记做:1R
    3. 将MAR所指主存中的内容经数据总线送入MDR,记做:M(MAR)MDR
    4. 将MDR中的内容(此时是指令)送入IR,记做:(MDR)IR
    5. CU发出控制信号,形成下一条指令地址,记做:(PC)+1PC

    取址周期

    间址周期

    间址周期执行流程有以下几个阶段:

    1. IR或MDR种的指令的地址码送入MAR,记做:Ad(IR)MARAd(MDR)MAR
    2. CU发出控制信号,启动主存做读操作,记做:1R
    3. 将MAR所指主存中的内容经数据总线送入MDR,记做:M(MAR)MDR
    4. 将有效地址送至指令的地址码字段,记做:(MDR)Ad(IR)

    间址周期

    中断周期

    执行周期的任务是根据IR中的指令字的操作码和操作数通过ALU操作产生执行结果。不同指令的执行周期操作不同,因此没有统一的数据流向。所以之后做讨论。

    所谓中断就是暂停当前任务取完成其他任务。为了能够恢复当前任务,需要保存断点。一般使用堆栈来保存断点,这里用SP表示栈顶地址,假设SP指向栈顶元素,进栈操作是先修改指针,后存入数据。这个保存断点过程具体实现如下:

    1. CU控制将SP减1,修改后的地址送入MAR记做:(SP)1SP(SP)MAR 本质上是将断点存入某个主存存储单元,假设其地址为a,故可记做:aMAR
    2. CU发出控制信号,启动主存做写操作,记做:1W
    3. 将断点(PC内容)送入MDR,记做:(PC)MDR
    4. CU控制将中断服务程序的入口地址(由向量地址形成部件产生)送入PC,即PC指向中断程序第一行。各个中断处理程序的存放地址称为向量地址。记做:PC

    中断周期

    2.3 指令执行方案

    显然不同指令指令周期长度不同,当希望可以连续执行多条指令的时候有以下几个方案:

    3. 数据通路

    数据通路:数据在功能部件之间传送的路径。

    数据通路的基本结构:

    1. CPU内部单总线方式:将所有寄存器的输入端和输出端都连接到一条公共的通路上。在同一时刻只允许两个部件之间进行数据交换。

      CPU内部单总线方式

    2. CPU内部多总线方式:将所有寄存器的输入端和输出端都连接到多条公共的通路上。

    3. 专用数据通路方式:由于ALU有两个输入口,所以每个寄存器要提供两个连线,这里的两根连线是泛指,如果一个寄存器16bit,那每一边都需要16根连线总共32根连线连接ALU。

      ALU连线通路

    下面对单总线方式和专用数据通路方式做详细探讨。

    3.1 CPU内部单总线方式

    无论哪种方式其目的都是为了实现数据流动,这要是数据通路存在本质。一般来说数据流动可以分为三类:

    1. 寄存器与寄存器之间的流动
    2. 寄存器与主存之间的数据流动
    3. 寄存器与ALU算术逻辑单元之间的流动

    之前提到过内部总线和系统总线概念:

    单总线连接方式如下:

    单总线方式

    注意:上图中inout信号都与CU控制总线相连,CU控制总线给一个对应信号,就可以执行对应的in/out操作。

    寄存器之间的数据传送

    如果将上图PC内容送到MAR中,实现传送操作流程及控制信号为:

    1. 首先让CU与PCout相连接的信号发出高电平信号,让其有效。这样PC线路数据被打通,其数据输出到内部总线上。记作PCBUS。这里的BUS即内部总线。
    2. 之后通过CU控制信号将MARin打通,在总线上的数据会输送到MAR中。记作BusMAR

    标准答题流程:

    标准答题流程

    也可以写为:(PC)BusMAR。有的教材也写作PCBugMAR

    其他寄存器之间的数据流通原理类似。先让out信号有效留出,再让in信号有效输入。

    主存与寄存器之间的数据传送

    比如IR从主存读取指令,实现传送操作的流程及控制信号为:

    主存从寄存器中读取信息

    单总线方式1

    执行算术或逻辑运算,比如一条加法指令,微操作序列及控制信号为:

    加法指令执行过程

    单总线方式2

    上面CU单元通过不同控制信号完成每一次的微操作。上面每一个微操作都至少消耗一个时钟周期。

    单总线方式例题

    设有如图所示的单总线结构,分析指令ADD (R0), R1的指令流程和控制信号。其中(R0)代表R0寄存器中存放的是形式地址。

    单总线方式例题

    上图中MemR表示主存读信号,MemW表示主存写信号。

    操作分三个周期:取址周期、间址周期、执行周期

    3.2 专用数据通路

    在任何两个需要流通数据的部件之间都建立专用的数据通路。

    专用数据通路

    上图中的Cn指的是控制信号。基于这种方式取出指令周期如下:

    例题:下图是一个简化了的CPU与主存连接结构示意图(图中省略了所有的多路选择器)。其中有一个累加寄存器(ACC)、一个状态数据寄存器和其他4个寄存器:主存地址寄存器(MAR) 、主存数据寄存器(MDR) 、程序寄存器(PC) 和指令寄存器(IR) ,各部件及其之间的连线表示数据通路,箭头表示信息传递方向。

    专用数据通路例题

    1. 写出上图中a,b,c,d四个寄存器的名称。

      d能自动+1,所以是PC

      PC输送的是地址,所以送给MAR,故c是MAR

      b与微操作信号发生器直接连接,所以b是指令寄存器IR

      只有MDR与主存会发生读/写的操作,所以a是MDR

      专用数据通路例题1

    2. 简述图中取指令的数据通路

      PCMAR。由于指令地址放在PC中,所以PC数据送给MAR。

      M(MAR)MDR

      (MDR)IR

      OP(IR)微操作发生器。将IR中的指令送给微操作发生器进行解析

      (PC)+1PC

    3. 简述数据在运算器和主存之间进行存/取访问的数据通路。即存/取数据放入ACC中。

      设数据地址已经在MAR中

      取:M(MAR)MDR

      (MDR)ALUACC

      存:(ACC)MDR

      (MDR)M(MAR)

    4. 简述完成指令LDA X的数据通路(X为主存地址,LDA的功能为(X)ACC)

      XMAR

      M(MAR)MDR

      (MDR)ALUACC

    5. 简述完成指令ADD Y的数据通路(Y为主存地址,ADD的功能为(ACC)+(Y)ACC)

      YMAR

      M(MAR)MDR

      (MDR)ALU,(ACC)ALU

      ALUACC

      由于上一题ACC中已经有X,所以这里直接放入ALU完成加法操作。

    6. 简述完成指令STA Z的数据通路(Z为主存地址,STA的功能为(ACC)Z)

      ZMAR

      (ACC)MDR

      (MDR)M(MAR)

    4. 控制器的设计

    通过之前学习知道高级语言编写的代码会翻译成与之对应的指令。而每条指令的执行会被分为四个周期:取址周期(FE=1)、间址周期(IND=1)、执行周期(EX=1)、中断周期(INT=1)。

    高级语言指令周期

    在一个机器周期内需要通过若干个机器序列来完成这一个周期内需要完成的事情。而每一个机器周期又有若干个时钟周期组成,每个时钟周期又称为节拍。控制单元CU会在每一个节拍内发出一个微命令(信号),用来完成对应的操作。如:微命令1使得PCout,MARin有效,从而完成微操作1(PC)MAR

    所以微命令和微操作概念是一一对应的。微操作更多是在描述工作要完成什么内容;而微命令是指要完成这个工作所需要发出的控制信号。所以每发出一条微命令就会完成与之对应的一个微操作。并且有的微操作是有可能并行进行的,比如采用专用通路方式,在这种结构下可以完全让多个寄存器之间的数据同时进行并行的流动。因此每个节拍可以完成并行的不冲突的操作。

    四个周期对应微操作

    上图从上到下依次对应四个周期。每一个周期都有三个节拍,在第一个取址周期内第一个节拍T0可以完成两个微操作,也就是让CU同时发出两个微命令,让这两个微操作并行进行。并且可以看到在执行周期和中断周期T0节拍内什么都没做,即这两个周期只需要两个节拍就可以完成工作,但还是有三个节拍,这也就意味着在这个例子中采用了定长机器周期这样一个策略,可以让电路设计更简单。

    这个例子有以下特质:

    1. 一个节拍内可以并行完成多个"相容的"微操作。即如果两个微操作执行不会相互冲突,不会相互制约,那么就可以把多个微操作安排在一起。这样可以使CU在一个节拍内完成更多的事情。
    2. 同一个微操作可能在不同指令的不同阶段被使用。如上图的黄色部分间址周期内的T0部分,微操作2在上一个取址周期内T0节拍也使用到。如:M(MAR)MDR这个操作在很多周期内都会重复使用到。
    3. 不同指令的执行周期所需节拍数各不相同。为了简化设计,选择定长的机器周期,以可能出现的最大节拍数为准(通常以访存所需节拍数作为参考)。上面例子中节拍数是3
    4. 若实际所需节拍数较少,可将微操作安排在机器周期末尾几个节拍上进行。如上面的执行周期和中断周期。

    4.1 硬布线控制器设计

    综上所述设计控制器核心思想是:根据指令操作码、目前的机器周期、节拍信号、机器状态条件,即可确定现在这个节拍下应该发出哪些"微命令"。

    设计思路

    硬布线控制器是是控制当中的一种,即用纯硬件的方式设计控制器。

    设计思路:

    接着CU可以根据指令操作码、目前的机器周期、节拍信号、机器状态条件,即可确定现在这个节拍下应该发出哪些"微命令"。所以控制单元每个输出的控制信号对应一个微命令,也就是对应一个操作。

    硬步线控制器设计5

    如:要让C1对应微操作(PC)MAR,则将其接到PCout,MARin上即可。接下来要解决的问题是什么情况下CU会发出对应的命令。

    实际上所有指令的取址周期,T0节拍下一定要完成(PC)MAR这个操作。所以可知逻辑表达式C1=FE·T0。之后可以得到这个门电路:

    硬步线控制器设计6

    接着将这个门电路集成在CU中,节拍发生器T0连接与门一段,FE触发器连接在另一端。与门输出端连接上C1。这样在T0=1&&FE=1时,C1会发出一个高电平信号。即发出(PC)MAR微操作所对应的微命令。

    所以只要可以写出某个微命令所对应的逻辑表达式,就能确定这个微命令所对应的电路怎么设计。前面(PC)MAR这个逻辑表达式很简单可以得到,实际情况下会有很复杂的情况如:M(MAR)MDR

    M(MAR)MDR对应的微命令逻辑表达式:

    FE·T1+IND·T1(ADD+STA+LDA+JMP+BAN)+EX·T1(ADD+LDA)

    该逻辑表达式对应的电路:最右边是一个或门。

    逻辑表达式对应的电路

    FE·T1:当FET1进行与操作表示在取址阶段的T1节拍需要进行M(MAR)MDR微操作对应的命令。

    EX·T1(ADD+LDA):当EX=1表示指令处于执行阶段,(ADD+LDA)表示加法或这取数(取到ACC中)指令。如果当前处于加法指令或者取数指令的执行阶段,并且处于T1节拍,就执行对应的M(MAR)MDR微操作对应的命令。

    设计方式

    接下来要探讨的是如何得到与一个微操作所对应的电路,知道这个过程就能知道硬布线控制器如何设计。

    其设计步骤可以分为四步:

    1. 分析每个阶段的微操作序列(取值、间址、执行、中断四个阶段)。确定哪些指令在什么阶段、在什么条件下会使用到的微操作。
    2. 选择CPU的控制方式。假设采用同步控制方式(定长机器周期),一个机器周期内安排3个节拍。
    3. 安排微操作时序。如何用3个节拍完成整个机器周期内的所有微操作?
    4. 电路设计。确定每个微操作命令的逻辑表达式,并用电路实现。

    第一步:分析每个阶段的微操作序列

    中断周期微操作不再分析,原理类似。

    第二步:采用定长机器周期,为T0,T1,T2

    第三步:安排微操作时序。将以上指令每个周期安排在三个节拍内完成。

    安排微操作时序原则:

    1. 微操作的先后顺序不得随意更改。取数之前必须将地址放入MAR
    2. 被控对象不同的微操作尽量安排在一个节拍内完成。如:(PC)MAR,1R,第一个指令控制对象是MAR,第二个指令控制对象是主存。所以这两个指令控制对象不同,可以安排在一个节拍内完成。
    3. 占用时间较短的微操作尽量安排在一个节拍内完成,并允许有先后顺序。因为CPU速度很快,因此一个时钟周期内就算两个指令有先后顺序,也可以几乎同时完成。

    第四步:电路设计。设计步骤:

    1. 列出操作时间表。列出在取指、间址、执行、中断周期,T0T1T2节拍内有可能用到的所有微操作。
    2. 写出微操作命令的最简表达式。
    3. 画出逻辑图

    设计硬布线控制器步骤总结:

    1. 分析每个阶段的微操作序列
    2. 选择CPU的控制方式
    3. 安排微操作时序
    4. 电路设计 (1)列出操作时间表 (2)写出微操作命令的最简表达式 (3)画出逻辑图

    硬布线控制器特点:

    指令越多,设计和实现就越复杂,因此一般用于RISC(精简指令集系统)。

    如果扩充一条新的指令,则控制器的设计就需要大改,因此扩充指令较困难。

    由于使用纯硬件实现控制,因此执行速度很快。微操作控制信号由组合逻辑电路即时产生。

    4.2 微程序控制器的基本原理

    用高级语言写的代码会被翻译成一系列对等的指令。而每条指令执行可以被细分为一个个微操作。可以把一个时序之内同时进行的微操作用一个微指令来指令

    微指令

    如上图微指令a,可以完成微操作1,2。由一整个微指令序列就构成了一个微程序。

    所以程序是由指令序列构成的。微程序是由微指令序列组成,每一种指令对应一个微程序。

    要注意的是机器指令是对程序执行步骤的描述而微指令是对指令执行步骤的描述。

    可以借鉴之前采用"存储程序"的思想,CPU出厂前将所有指令的"微程序"存入"控制器存储器"中。

    注意:微命令与微操作一一对应。而微指令中可能包含多个微命令。

    另外微程序和机器指令也是一一对应的,一种机器指令会对应一个微程序,而一个微程序有多个指令序列构成。所以可以说机器指令是对微指令功能的封装。

    所以微指令格式是:用n个bit表示当前微指令所对应的微操作是哪几个;另外还需要mbit的顺序控制字段,指明下一条微指令的地址。

    微指令格式

    微程序控制器基本结构

    CU控制单元内部引入控制寄存器(CM)。这个CM用于存放各指令对应的微程序,控制存储器可用只读存储器ROM构成,通常在CPU出厂时就把所有微程序写入。每一种机器指令会对应一个微程序,而一个微程序会与一系列微指令序列构成。这些微指令序列在CM中会顺序存放。

    微指令序列存放

    为了指明接下来要执行的微指令存放在什么位置,要引入地址寄存器CMAR。别名叫μPC,微地址寄存器,接收微地址形成部件送来的微地址,为在CM中读取微指令作准备。

    CU内部结构

    对于CMAR来说,同样也需要将内部地址送给地址译码器。其功能是将地址码转化为存储单元控制信号。

    之后从CM中取出一条微指令,也需要放到CMDR中,别名叫μIR,用于存放从CM中取出的微指令,它的位数同微指令字长相等。

    还需要一个微地址形成部件,它的作用是产生初始微地址和后继微地址,以保证微指令的连续执行。根据机器指令操作码部分来确定它所对应的微指令序列对应的首地址。

    最后需要一个顺序逻辑,因为微指令序列不一定是顺序的执行。如果有中断发生,微指令序列执行顺序会发生变化。

    CU构成

    所以执行一条指令过程是,首先把指令的操作码送给微地址形成部件,用来确定这条指令所对应的微指令序列的起始地址。接着根据顺序逻辑的标志信息确定接下来执行微指令的存放地址,将微指令地址放入CMAR中。之后经过地址译码器译码之后选中CMAR所指向的那条微指令。之后取出这条微指令将其放入CMDR中,而CMDR中包含微指令两个部分信息,第一部分用来描述微指令对应的控制信号,第二部分用于描述接下来要执行的微指令地址,称为下地址。所以执行完这条微指令后,需要把下地址信息送给顺序逻辑,之后顺序逻辑根据标志信息,再决定下一条微指令的存放地址。之后循环。

    CU执行流程

    当前CU会发出什么信号是根据CMDR中的控制字段决定的。如果所有指令的取址周期、间址周期、中断周期所对应的微指令序列都一样,那么可以共享使用。基于这个原因在CM存储器中存储的微指令序列,通常来说取址周期所对应的微程序断只有一份,因为所有机器指令执行在取址阶段要做的微操作都是一样的。所以间址周期和中断周期也都是只存一份。只有执行周期所对应的微程序每个机器指令都是不一样的。

    微程序控制器的工作原理

    分析取数指令LAD X的执行流程:

    取数指令执行周期

    考试常考点:

    之前说过取址周期、间址周期、中断周期都是一样的,所以微程序是公用共享的。故对于取址周期来说如果某条指令系统中有n条机器指令,则CM中微程序段的个数至少是n+1个。

    因为n条指令对应的执行周期微程序序列都不一样,因此需要设计n个微程序来分别描述这n条指令执行周期要做的事情。另外还需要一个公用的取址周期,所以是n+1。z

    这里没算间址周期和中断周期是因为一些早期的CPU、物联网设备的CPU可以不提供间接寻址和中断功能,因此这类CPU可以不包含间址周期、中断周期的微程序段。

    注意:物理上取指周期、执行周期看起来像是两个微程序,但逻辑上应该把它们看作一个整体。因此,一条指令对应一个微程序的说法是正确的。故取址、间址、执行和中断四个周期组成的微程序段看作逻辑上的一个整体,即微程序。

    指令周期:从主存取出并执行一条机器指令所需的时间。用于描述指令的执行速度。

    微周期(微指令周期):从控制器存储器取出一条微指令并执行相应微操作所需的时间。用于描述微指令执行速度。

    微指令设计

    如何根据一条微指令来发出相应的控制信号。通过之前的学习可以知道微命令与微操作是一一对应的,一个微命令对应一根输出线。并且有的微命令是可以并行执行的,因此一条微指令可以包含多个微命令。

    引入两个概念:

    1. 相容性微命令:可以并行完成的微命令
    2. 互斥性微命令:不允许并行完成的微命令。

    微指令的格式有三种:水平型微指令、垂直型微指令和混合型微指令。

    4.3 微指令的编码方式

    重点探讨水平型微指令格式如何设计操作控制字段。即如何用若干个二进制信息表示一系列控制信号。

    微指令的编码方式又称为微指令的控制方式,它是指如何对微指令的控制字段进行编码,以形成控制信号。编码的目标是在保证速度的情况下,尽量缩短微指令字长。

    直接编码方式

    又称为直接控制方式。即在微指令的操作控制字段中,每一位代表一个微操作命令。可以某位为1表示该控制信号有效。

    直接编码

    如上图如果像完成(PC)MAR1R两个指令,只需要将其对应的控制字段第一位和最后一位为1,其他全部为0即可。

    优点:简单、直观,执行速度快,操作并行性好。

    缺点:微指令字长过长,n个微命令就要求微指令的操作字段有n位,造成控存容量极大。

    字段直接编码

    将微指令的控制字段分成若干"段",每段经译码后发出控制信号。

    微命令字段分段的原则:

    1. 互斥性微命令分在同一段内,相容性微命令分在不同段内。
    2. 每个小段中包含的信息位不能太多,否则将增加译码线路的复杂性和译码时间。
    3. 一般每个小段还要留出一个状态,表示本字段不发出任何微命令。因此,当某字段的长度为3位时,最多只能表示7个互斥的微命令,通常用000表示不操作。

    字段直接编码

    上图(PC)MAR1R这两个微操作是可以并行执行的。所以需要将这两个微操作放到不同的段中,这两个微操作在与之相对应的段中会有一个特定的编码,这个编码经过译码器的编码后就会发出与这两个微操作相对应的控制信号。并且这两个微命令的控制信号是并行发出的。

    字段直接编码2

    上图(PC)+1PC(PC)MAR是互斥操作,所以可以放在同一段中,所以对第二个操作(PC)+1PC进行一个不一样的编号,如010。所以对于这两个操作信号不可能同时由译码器发出。

    使用这种编码方式可以有效的将微指令总体长度变短。

    例:某计算机的控制器采用微程序控制方式,微指令中的操作控制字段采用字段直接编码法,共有33个微命令,构成5个互斥类,分别包含731256个微命令,则操作控制字段至少有多少位?

    1个互斥类有7个微命令,要留出1个状态表示不操作,所以要有23=8种不同的状态,故需要3个二进制位。依次类推,后面4个互斥各需要表示4,13,6,7种不同的状态,分别对应2,4,3,3个二进制位。所以操作控制字段的总位数为3+2+4+3+3=15位。如果采用第一种直接编码方式,则需要33个位,所以显然字段直接编码比直接编码方式所需要的指令字段更少。

    所以字段直接编码优点:可以缩短微指令字长。缺点:要通过译码电路后再发出微命令,因此比直接编码方式慢。

    字段间接编码方式

    一个字段的某些微命令需由另一个字段中的某些微命令来解释,由于不是靠字段直接译码发出的微命令,故称为字段间接编码,又称隐式编码。

    字段间接编码方式

    如上图,当字段2经过译码器译码之后,并不是直接发出这个字段所对应的控制信号,而是会把这个译码信号输送给下一级的译码器。经过下一级的译码器在经过一次处理后才发出最终的控制信号。

    优点::可进一步缩短微指令字长。

    缺点:削弱了微指令的并行控制能力,故通常作为字段直接编码方式的一种辅助手段。

    微指令地址形成方式

    一个微地址由控制字段和下地址两个部分构成,上面介绍了控制字段的设计,接下来介绍下地址的形成方式。

    例题:某计算机采用微程序控制器,共有32条指令,公共的取指令微程序包含2条微指令,各指令对应的微程序平均由4条微指令组成,采用断定法(下地址字段法)确定下条微指令地址,则微指令中下地址字段的位数至少是多少位?

    即总共需要存储多少条微指令,由于每条指令对应的微程序由4条微指令组成,并且有2条公共的取指令程序。所以总共需要存储

    32×4+2=130

    由于27=128,不够存放,所以需要8个二进制位。即下地址字段的位数至少是8位。

    4.4 微程序控制单元的设计

    步骤和硬布线控制器设计思路类似。

    设计步骤:

    1. 分析每个阶段的微操作序列

    2. 写出对应机器指令的微操作命令及节拍安排

      • 写出每个周期所需要的微操作(参照硬布线)

      • 补充微程序控制器特有的微操作:

        取指周期:Ad(CMDR)CMAROP(IR)CMAR

        执行周期:Ad(CMDR)CMAR

    3. 确定微指令格式

      根据微操作个数决定采用何种编码方式,以确定微指令的操作控制字段的位数。 根据CM中存储的微指令总数,确定微指令的顺序控制字段的位数。 最后按操作控制字段位数和顺序控制字段位数就可确定微指令字长。

    4. 编写微指令码点

      根据操作控制字段每-位代表的微操作命令,编写每- -条微指令的码点。

    第一步,以取址周期为例:

    取指周期微程序控制器的节拍安排 T0PCMAR

    T01R

    T1M(MAR)MDR

    T1(PC)+1PC

    T2MDRIR

    T2OP(IR)

    硬布线与微程序控制器设计对比:

    硬布线与微程序控制器设计对比

    唯一区别在最后对于硬布线控制器是把指令的操作码部分送给指令译码器ID,之后ID会发出与操作码相对应那根线的选通信号。

    而对于微程序控制器来说只需要把操作码送给微地址形成部件,之后由微地址形成部件来指明这条指令在接下来的执行周期所对应的微程序的起始地址。

    微程序控制单元设计

    以上给出的三条操作指令并不完善,还需要考虑如何读出这三条微指令,及如何转入下一个机器周期。

    对于取址周期第一条微指令会固定存放在0号地址单元,所以第一条微指令是由硬件自动给出的。而之后指令地址会记录在当前指令的下地址中。所以在执行完微指令后还需要穿插一个微操作,将当前微指令的下地址信息送到CMAR中Ad(CMDR)CMAR。这样一个微操作执行也需要消耗一个节拍。

    另一方面还需要考虑如何转入下一个机器周期。假设取址周期结束后会直接进入执行周期,由于不同指令在执行阶段微程序各不相同,所以在取址阶段的执行结束后,还需要根据当前指令的操作码确定这个指令所对应的微程序的起始地址。因此把指令操作码送给微地址形成部件后,还需要消耗一个节拍,把微地址形成部件指明的地址信息放入CMAR中,即OP(IR)CMAR

    所完整取指周期微程序控制器的节拍安排如下:

    微程序控制单元设计3

    显然微程序控制器需要5个节拍,而硬布线控制器只需要3个节拍,所以微程序控制器的速度比硬布线控制器更慢。

    第二步:在第一步得到的微操作序列基础上,把可以并行的微操作安排在一个节拍内进行。

    之后由于采用微程序控制器,需要加入几个特有的微操作:

    第三步:需要确定微指令的格式

    第四步:编写微指令码点。如采用直接编码方式,可以根据第一步每条微指令所需要执行的微操作信息确定每条微指令的控制码部分哪一位需要为1

    接下来把这些微指令序列放到CM中即可。

    4.5 微程序设计分类与两种设计方式对比

    静态微程序设计和动态微程序设计:

    毫微程序设计:微程序设计用微程序解释机器指令。而毫微程序设计用毫微程序解释微程序。

    硬布线与微程序设计比较

    对比项目微程序控制器硬布线控制器
    工作原理微操作控制信号以微程序的形式
    存放在控制存储器中,执行指令时
    读出即可
    微操作控制信号由组合逻辑电路
    根据当前的指令码、状态和时序,
    即时产生
    执行速度
    规整性较规整繁琐、不规整
    应用场合CISC CPURISC CPU
    易扩展性易扩充修改困难

    5. 指令流水线

    指令流水线可以对指令的执行过程进行优化。

    一条指令的执行过程可以分成多个阶段(或过程)。根据计算机的不同,具体的分法也不同。最简单划分方法是划分为三个阶段:取指阶段、分析阶段、执行阶段。

    三个阶段

    一条指令在不同的阶段所需要使用到的硬件部件是不一样的:

    1. 取指阶段:根据PC内容访问主存储器,取出一条指令送到IR中。
    2. 分析阶段:对指令操作码进行译码,按照给定的寻址方式和地址字段中的内容形成操作数的有效地址EA,并从有效地址EA中取出操作数。
    3. 执行阶段:根据操作码字段,完成指令规定的功能,即把运算结果写到通用寄存器或主存中。

    特点是每个阶段用到的硬件不一样。

    为了方便分析,设取指、分析、执行3个阶段的时间都相等,用t表示,按以下几种执行方式分析n条指令的执行时间:

    引入指令流水线:

    上图是指令执行过程图。

    指令执行过程图

    横坐标是指令执行时间t,纵坐标是指令序列。这种图主要用于分析旨令执行过程以及影响流水线的因素。

    还有另一种描述指令执行过程的图,时空图:

    时空图

    横坐标表示时间t,纵坐标表示不同的执行阶段。这种图主要用于分析流水线的性能。

    大体上可以用吞吐率、加速比、效率三个指标评价流水线的性能。

    5.1 影响指令流水线的因素

    上面介绍指令流水线的时,各个阶段都是理想情况,这些导致不完美因素就是要探讨的内容。

    为了方便讨论先引入五段式指令流水线:

    五段式指令流水线

    即一条指令执行分为IF,ID,EX,M,WB五个阶段。

    这种五段式指令流水线是考试最常考结构,这种流水线被称为MIPS架构所提出的指令流水线,是世界上第一个精简指令集(RISC)系统。

    总之在MIPS架构下一条指令执行会被划分为五个阶段,有的指令可能会跳过某些阶段(如访存阶段)。然而为了方便指令流水线安排,所有指令都会安排为五个这样的机器周期。所以在MIPS架构下一定都是五个机器周期。

    另一个方面每个周期花费时间不一样。

    五段式指令流水线耗时

    各个部件耗时假设为上图所示时间。为方便流水线的设计,将每个阶段的耗时取成一样,以最长耗时为准。即此处应将机器周期设置为100ns。所以在MIPS架构下包含的周期数相同都是五个机器周期,并且每个机器周期长度都相同,这样可以方便安排指令流水线。

    现在产生一个问题,如上图中EX阶段应该是在200ns时,才能获得需要的数据。但由于前面的ID阶段实际只需要的80ns,所以为了让第三阶段EX能赶在200ns时候流出,就需要在各个阶段之间添加暂存寄存器。

    五段式指令流水线耗时2

    上面蓝色方框的部件就是暂存寄存器其称为缓冲寄存器,流水线每一个功能段部件后面都要有一个缓冲寄存器,或称为锁存器,其作用是保存本流水段的执行结果,提供给下一流水段使用。

    另外需要注意的是上图CPU中的Cache分为两个模块Instruction Cache(存放指令)和Data Cache(存放数据)。指令和数据用两个独立的Cache模块存放是很有意义的,可以使第一阶段和第四阶段所需要使用的硬件部件可以并行工作。

    上图含义是:取指阶段根据PC所指向的位置去Instruction Cache中取出数据,取出的数据放入锁存器中。接着进入第二指令译码阶段,这个阶段除了完成指令译码的工作外,还会完成取数的工作,取数指的是将这条指令所需要的操作数从通用寄存器中取出放入锁存器A,B中。接着第三个执行阶段需要用算术逻辑单元ALU处理前一个阶段取出的操作数A,B。上图中第二阶段还有一个锁存器Imm,是用来存放立即数的。第三个阶段ALU计算后会将输出的结果放到锁存器当中,这个运算结果可能会写入主存或者直接写入寄存器。如果直接写入寄存器第五个阶段写回阶段会将运算结果写回到通用寄存器中。

    第二个阶段有可能对某个通用寄存器进行读操作,最后一个阶段有可能会把某个数据写回到通用寄存器。这两个阶段对寄存器的读和写两个操作可能造成一些问题,即影响流水线的因素。

    因素可以分为三类:

    1. 结构相关(资源冲突)
    2. 数据相关(数据冲突)
    3. 控制相关(控制冲突)

    结构相关因素

    又叫资源冲突。由于多条指令在同一时刻争用同一资源而形成的冲突称为结构相关。

    结构相关

    上图Load指令在第四个阶段读取主存会和Instr3第一阶段取指阶段读取主存发生冲突。同样第一条指令第五个阶段会对某个寄存器写回操作,而Instr3指令的第二个阶段读是取寄存器,如果两个指令访问是一个寄存器就会产生冲突。

    解决方法:

    1. 后一相关指令暂停一周期

    2. 资源重复配置:数据存储器+指令存储器

      即如果将指令和数据分别放到两个不同的存储器中,那么第一阶段取指阶段和第四个阶段访存阶段所需要访问的寄存器一定是不相同的。

    数据相关

    又叫数据冲突。数据相关指在一个程序中,存在必须等前一条指令执行完才能执行后一条指令的情况,则这两条指令即为数据相关。

    数据相关

    上图第一条执行一个加法操作,将r2+r3的结果放回r1。后面四个操作分别是减法、与、或、异或操作。可以观察到第二三四条指令会用到第一条指令中r1内存放的数据,所以必须要等到第一条指令执行完后面的才能执行,这就是同步问题,必须保证两个工作一前一后地完成。上面第二三四条指令都在第一条指令没有完成前先读取r1中地数据,所以会失败。而最后一条指令在第一条指令完成后进行,所以不会失败。

    解决方法:

    1. 把遇到数据相关的指令及其后续指令都暂停一至几个时钟周期,直到数据相关问题消失后再继续执行。可分为硬件阻塞(stall)和软插 入"NOP"两种方法。

      采用硬件阻塞:

      数据冲突解决方法

      如果两个指令之间存在数据冲突使用硬件阻塞方式,硬件系统会添加如上图所示地"气泡"。将第二条指令执行时间往后拖三个节拍。此时后面指令就不会造成数据冲突。

      同时也可以用软件NOP指令地方式解决。

      数据冲突解决方法2

      执行指令时,编译器发现两个指令之间会有数据冲突关系,那么编译器会在这两条指令中间插入三条空指令。每一个空指令的执行也会经过五个周期。之后的指令就不会造成数据冲突问题。

    2. 数据旁路技术

      又叫做转发机制。其大致思路是在第一条指令ALU进行加法运算结果就已经出来了,此时会连出一个数据旁路,让结果直接送回ALU的其中一个输入端,作为下一条指令的输入。这样就不需要等待上一条指令的写回操作。

      数据冲突解决方法3

    3. 编译优化

      可以通过编译器调整指令顺序来解决数据相关。

      第一条指令结果会被后面指令使用到,如果第五条指令的后面还有其他指令,而这些其他指令又不需要前面几条指令的运算结果,此时就可以将后面几条指令安排在第一条指令之后运行。这样当第二个指令执行时,系统其实已经将第一条指令五个周期全部执行完毕,所以就不会产生数据冲突了。

    控制相关

    又叫控制冲突。当流水线遇到转移指令和其他改变PC值的指令而造成断流时,会引起控制相关。

    控制相关

    假如现在要执行的是条件转移指令,这条指令存放在上图地址为12的位置,下一条指令是16位置。但是现在由于条件转移指令生效,此时跳转到地址为1000的地方,即PC1000。这样前面三条指令,即地址16,20,24的指令是不应该执行的,这就是控制相关问题。出来转移类指令会造成断流,CALL(函数调用)、函数返回、中断程序等都会造成程序的断流,都会产生控制相关的问题。

    解决方法:

    1. 转移指令分支预测。与两种预测方式:简单预测(永远猜true或false)、动态预测(根据历史情况动态调整)。

    2. 预取转移成功和不成功两个控制流方向上的目标指令

      由于条件转移指令,有可能导致程序执行流往两个方向走,那么将两个方向所用到的指令都预取出来。采用这种方法可能会改变硬件,如多增加两个寄存器等。

    3. 加快和提前形成条件码。

    4. 提高转移方向的猜准率

      是对第一种方法优化。

    5.2 指令流水线的分类

    根据流水线使用的级别的不同,流水线可分为部件功能级流水线、处理机级流水线和处理机间流水线。

    按流水线可以完成的功能,流水线可分为单功能流水线和多功能流水线。

    按同一时间内各段之间的连接方式,流水线可分为静态流水线和动态流水线。

    按流水线的各个功能段之间是否有反馈信号,流水线可分为线性流水线与非线性流水线。

    5.3 流水线的多发技术

    1. 超标量技术

      每个时钟周期内可并发多条独立指令,即同一时刻同时执行多条指令,是一种空分技术。要想不出现冲突问题,就要配置多个功能部件。并且不能调整指令的执行顺序。

      超标量技术

      通过编译优化技术,把可并行执行的指令搭配起来。

      由于指令的排列是由编译器确定的,因此编译器在得到编译序列的时候要考虑到哪些指令可以并行执行。可以将其搭配在一起。因此对编译优化要求很高。

    2. 超流水技术

      在一个机器周期内再分段。一个机器周期内一个功能部件使用多次,是一种时分复用技术。

      超流水技术

      同样不能调制指令的执行顺序。要靠编译程序解决优化问题。上图将每一个机器周期又分为三段,所以速度上提升3倍。

    3. 超长指令字技术

      由编译程序挖掘出指令间潜在的并行性,将多条能并行操作的指令组合成一条超长指令,具有多个操作码字段的超长指令字(可达几百位)

      超长指令字

      显然多种操作想要同时进行就必须提供多个相互独立的部件。

    5.4 五段式指令流水线

    前面影响指令流水线的因素介绍过五段式指令流水线基本概念。

    这里会介绍常见五类指令:运算类指令、LOAD指令、STORE指令、条件转移指令、无条件转移指令详细分析这五类指令如何根据五个功能段完成相应的工作。

    运算类指令

    运算类指令在不同阶段工作:

    五段式指令流水线耗时

    指令举例:

    功能汇编格式具体描述
    加法指令(两个寄存器相加)ADD Rs,Rd(Rs)+(Rd)Rd
    加法指令(寄存器与立即数相加)ADD #996,Rd996+(Rd)Rd
    算术左移指令SHL Rd(Rd)<<<2Rd

    上面指令在五个阶段执行如下:

    LOAD指令

    功能汇编格式具体描述
    将指定地址中的数据放到某个寄存器中LOAD Rd,996(Rs)(996+(Rs))Rd

    上面指令在五个阶段执行如下:

    为了保证流水线的流畅工作,通常访问主存时候,大概率都能在Cache中找到想要的数据。

    通常在RISC处理器只有取数指令LOAD存数指令STORE才能访问主存。

    STORE指令

    功能汇编格式具体描述
    寄存中的值存放会回主存中STORE Rs,996(Rd)Rs(996+(Rd))

    上面指令在五个阶段执行如下:

    条件转移指令

    功能汇编格式具体描述
    两个寄存器值相等就需要进行转移beq Rs,Rt,#偏移量若(Rs)==(Rt),则(PC)+指令字长+(偏移量×指令字长)PC
    否则(PC)+指令字长PC
    两个寄存器值不相等就需要转移bne Rs,Rt,#偏移量若(Rs)!=(Rt),则(PC)+指令字长+(偏移量×指令字长)PC
    否则(PC)+指令字长PC

    上面指令在五个阶段执行如下:

    无条件转移指令

    功能汇编格式具体描述
    根据下一条指令的位置转移到指定位置jmp #偏移量(补码表示)(PC)+指令字长+(偏移量×指令字长)PC

    上面指令在五个阶段执行如下:

    例题:假设某指令流水线采用"按序发射,按序完成"方式,没有采用转发技术处理数据相关,并且同一寄存器的读和写操作不能在同一个时钟周期内进行。若高级语言程序中某赋值语句为x=a+bxab均为int型变量,它们的存储单元地址分别表示为[x][a][b]。该语句对应的指令序列及其在指令流中的执行过程如下图所示。

    五段式指令例题

    则这4条指令执行过程中I3ID段和I4IF段被阻塞的原因各是什么

    五段式指令例题2

    答案:I3I1I2存在数据相关;所以要在I2取数指令完成后才能进行编码阶段(ID)。

    I4IF段必须在I3进入ID段后才能开始,否则会覆盖IF段锁存器的内容。

    6. 多处理器系统

    6.1 SISD、SIMD、MIMD的基本概念

    基于指令流的数量和数据流的数量,对计算机体系结构分为SISD、SIMD、MISD和MIMD四类。常规的单处理器属于SISD,而常规的多处理器属于MIMD。

    1. 单指令流单数据流(SISD)结构

      SISD是传统的串行计算机结构,这种计算机通常仅包含一个处理器和一个存储器,处理器在一段时间内仅执行一条指令,按指令流规定的顺序串行执行指令流中的若干条指令。为了提高速度,有些SISD计算机采用流水线的方式,因此,SISD 处理器有时会设置多个功能部件,并采用多模块交叉方式组织存储器。前面介绍的内容多属于SISD结构。

      所以其特点是各指令序列只能并发、不能并行,每条指令处理一两个数据。

      SISD

      这总系统不支持数据级并行技术。即在同一时刻只能处理一两个特定数据,不可能并行处理很多数据。

      若要提升效率可以引入指令流水线,并且需设置多个功能部件,采用多模块交叉存储器。

    2. 单指令流多数据流(SIMD)结构

      SIMD是指一个指令流同时对多个数据流进行处理,一般称为数据级并行技术。这种结构的计算机通常由一个指令控制部件、多个处理单元组成。每个处理单元虽然都执行的是同一条指令,但每个单元都有自己的地址寄存器,这样每个单元都有不同的数据地址,因此,不同处理单元执行的同一条指令所处理的数据是不同的。一个顺序应用程序编译后,可能按SISD组织并运行于串行硬件上,也可能按SIMD组织并运行于并行硬件上。

      SIMD在使用for 循环处理数组时最有效,比如,一条分别对16对数据进行运算的SIMD指令如果在16个ALU中同时运算,则仅需一次运算时间就能完成运算。SIMD在使用case或switch语句时效率最低,此时每个执行单元必须根据不同的数据执行不同的操作。

      其特点是各指令序列只能并发、不能并行,但每条指令可同时处理很多个具有相同特征的数据。

      SIMD

      该系统是一种数据级的并行技术。

    3. 多指令流单数据流(MISD)结构

      MISD是指同时执行多条指令,处理同一个数据,实际上不存在这样的计算机。

    4. 多指令流多数据流(MIMD)结构

      其特点是各指令序列并行执行,分别处理多个不同的数据。是一种线程级并行(每个内核可以运行各自的进程,多个线程并行执行)、甚至是线程级以上并行(进程级并行)技术。

      进一步分类可以分为:多处理器系统(共享内存多处理器)和多计算机系统

      • 多处理器系统

        其特征是各个处理器之间,可以通过LOAD/STORE指令,访问同一个主存储器,可以通过主存相互传送数据。

        MIMD

        硬件之间多个处理器共享单一的物理地址空间。

      • 多计算机系统

        各个计算机之间主存是独立的,不能通过LOAD/STORE指令直接访问对方的存储器,只能通过"消息传递"相互传送数据。

        MIMD2

        每台计算机拥有各自的私有存储器,物理地址空间相互独立。

    5. 向量处理机(SIMD思想的进阶应用)

      其特点是条指令的处理对象是"向量"。擅长对向量型数据并行计算、浮点数运算,常被用于超级计算机中,处理科学研究中巨大运算量。

      向量处理器

      其硬件在成采用多个处理单元,多组"向量寄存器"。主存储器应采用"多个端口同时读取"的交叉多模块存储器。主存储器大小限定了机器的解题规模,因此要有大容量的、集中式的主存储器。

    总结:

    总结

    总结2

    6.2 硬件多线程概念

    先来看一下不支持多线程的普通处理器:

    不支持硬件多线程处理器

    这个处理器只包含一个同寄存器组和一个PC程序计数器,这就意味着在同一时间段内,在这个处理器当中只可能运行一段程序。如果现在两个线程的代码需要同时运行,那么对于线程A,PC指向该线程,现在要切换到线程B由于线程B与线程A指令代码都不一样,同时线程B也有可能用到寄存器,可能回覆盖掉线程A之前的运算结果。所以当从线程A切换到线程B时,需要将通用寄存器的值和PC值全部放到主存中,这样当切换回线程A时,才可能将线程A的信息进行恢复。这个保存和恢复过程给线程切换带来了不小的代价。

    再看可以支持硬件多线程的处理器:

    支持硬件多线程的处理器

    可以看到处理器中设置两个线程寄存器组,这样就可以把线程A和线程B的同时存储,这一切换时候就不需要把内容数据保存到主存中。

    接着看三种硬件多线程实现方式:

    功能细粒度多线程粗粒度多线程同时多线程(SMT)
    指令发射轮流发射各线程的指令
    (每个时钟周期发射一个线程)
    连续几个时钟周期,都发射同一线程的指令序列
    当流水阻塞时,切换另一个线程
    一个时钟周期内,同时发射多个线程的指令
    线程切换频率每个时钟周期切换一次线程只有流水线阻塞时才切换一次线程NULL
    线程切换代价高,需要重载流水线NULL
    并行性指令级并行,线程间不并行指令级并行,线程间不并行指令级并行,线程级并行

    六. 总线

    总线常常分为:地址总线、数据总线和控制总线。

    总线

    地址总线可以给硬件发送地址信息。数据总线可以传输数据。控制总线可以给部件发送控制信号。

    一个总线可以并行传递很多数据是因为每个总线中可能包含多根信号线。

    数据总线结构图

    上图是一根数据总线,内部有四根连线,所以可以同时传输4bit的信息。如果想要传输32bit信息,就要32根信号线。同时一时刻只能有一个部件通过数据总线发送数据,但是可以有多个部件接受数据。

    1. 总线的概述

    总线是一组能为多个部件分时共享的公共信息传送线路。

    共享是指总线上可以挂接多个部件,各个部件之间互相交换的信息都可以通过这组线路分时共享。

    分时是指同一时刻只允许有一个部件向总线发送信息,如果系统中有多个部件,则它们只能分时地向总线发送信息。

    总线定义

    早期计算机外部设备少时大多采用分散连接方式,即增加一个外部设备就要建立一条专门数据传送线路,这种方式不易实现随时增减外部设备。为了更好地解决I/O设备和主机之间连接的灵活性问题,计算机的结构从分散连接发展为总线连接,即每增加一个外部设备只需要将外部设备连接到总线上即可。

    当设计总线的时候需要关注以下特性:

    1. 机械特性:尺寸、形状、管脚数、排列顺序

    2. 电气特性:传输方向和有效的电平范围

      传输方向是指,CPU可以通过地址总线给主存指明此时要读写的地址。显然这个地址总线传输方向只能是由CPU传向主存。对于数据总线来说CPU要往主存中写数据都是通过数据总线传输,所以对于数据总线来说方向是双向的。

      有效电平范围:即高低电平在什么样范围内有效。

    3. 功能特性:每根传输线的功能(地址、数据、控制)

    4. 时间特性:信号的时序关系

    总线数据传输格式可以分为串行总线和并行总线。

    显然CPU与主存之间传送数据的总线式并行总线。串行规范常常用于USB。由于各个信号线之间的干扰问题,在发送数据的时候并行总线并不一定比串行要快。

    按总线功能(连接的部件)可以分为三类:片内总线、系统总线、通信总线。

    注意:数据通路表示的是数据流经的路径。而数据总线是承载的媒介。

    按时序控制方式可以分为两类:同步总线、异步总线

    本章重点探讨系统总线,系统总线经典结构有三种:单总线结构、双总线结构、三总线结构。

    2. 评价总线性能的指标

    评价总线性能指标有八种:总线的传输周期(总线周期)、总线时钟周期、总线的工作频率、总线的时钟频率、总线宽度、总线带宽、总线复用、信号线数。

    通过上面概念可以得到总线带宽公式

    线=线×线(bit/s)=线×(线/8)(B/s)

    由于总线工作频率和总线周期之间是倒数关系,所以

    线=线线(bit/s)=线/8线(B/s)

    注:总线带宽是指总线本身所能达到的最高传输速率。在计算实际的有效数据传输率时,要用实际传输的数据量除以耗时(校验位等)。

    例题:某同步总线采用数据线和地址线复用方式,其中地址/数据线有32根,总线时钟频率为66MHz,每个时钟周期传送两次数据(上升沿和下降沿各传送一次数据)。

    1. 该总线的最大数据传输率(总线带宽)是多少?

      每个时钟周期传送两次数据,所以工作频率是时钟频率的两倍,即总线工作频率=2×66MHz=132MHz

      总线宽度=32bit=4B

      总线宽度=总线工作频率×总线宽度=132×4MB/s=528MB/s

    2. 若该总线支持突发(猝发)传输方式,传输一个地址占用一个时钟周期,则一次"主存写"总线事务传输128位数据所需要的时间至少是多少?

      发送首地址占用1个时钟周期,128位数据需传输4次,占用2个时钟周期,且一个时钟周期=1/66MHz15ns

      故总耗时=(1+2)×15ns=45ns

    由公式线=线×线(bit/s)联系之前讲过串行与并行总线可知并行总线中为了保证数据的正确传输通常并行总线的工作频率不能太高,因为有信号干扰。而串行中线没有数据干扰,所以工作频率可以很高。所以两种线速度情况有以下两种:

    1. 工作频率相同时,串行总线传输速度比并行总线慢。
    2. 并行总线的工作频率无法持续提高,而串行总线可以通过不断提高工作频率来提高传输速度,最终超过并行总线。

    3. 总线的操作和定时

    总线同一时刻只能提供给一组设备使用。当一个设备获得总线控制权后,就可以利用总线对某一个从设备发出一定的命令,比如读写数据等。这对主设备和从设备之间怎么用电信号进行数据交流和时序安排就是这一节探讨的内容。

    用总线传一次数据,即总线周期需要四个阶段:

    1. 申请分配阶段:由需要使用总线的主模块(或主设备)提出申请,经总线仲裁机构决定将下一传输周期的总线使用权授予某一申请者。也可将此阶段细分为传输请求和总线仲裁两个阶段。
    2. 寻址阶段:获得使用权的主模块通过总线发出本次要访问的从模块的地址及有关命令,启动参与本次传输的从模块。
    3. 传输阶段:主模块和从模块进行数据交换,可单向或双向进行数据传送。
    4. 结束阶段:主模块的有关信息均从系统总线上撤除,让出总线使用权。

    而总线定时指的是总线在双方交换数据的过程中需要时间上配合关系的控制,这种控制称为总线定时,它的实质是一种协议或规则。即主模块与从模块在总线周期内进行四个阶段需要时间上的配合进行协调工作,如何进行它们在时间上有条不紊的配合这就是总线定时要探讨的问题。事实上总线定时就是要指定某一种协议或规则让数据的放松方和接受方都能按照统一规则进行数据交互。

    总线定时方案(协议)有四种:同步通信(同步定时方式)、异步通信(异步定时方式)、半同步通信、分离式通信。

    七. 输入/输出系统

    常见的输入设备有鼠标和键盘。常见的输出设备有显示器和打印机。而硬盘和光盘是即可输入又可输出的设备。这些所有的I/O设备可以统称为外部设备。

    在总线那一章中介绍过单总线结构:

    单总线结构关于IO设备

    I/O接口:又称I/O控制器、设备控制器,负责协调主机与外部设备之间的数据传输,这个控制器就是一块芯片,会被集成在主板上。

    USB控制器

    如上图外部设备通过I/O接口与CPU进行数据交互,这个I/O接口就是I/O控制器。上图又可以称为USB接口,因为通过USB连接线连接的,而电脑可以连接的设备多种多样因此控制不同的接口用到的I/O控制器也不一样。

    所以I/O控制器多种多样,也会制定相应的标准,如:用于控制USB设备的IO接口、用于控制SATA 3.0硬盘的I/O接口等。

    CPU是如何通过I/O接口与外设进行交互的:

    IO控制方式简介

    上面I/O接口内的功能部件有数据寄存器、控制寄存器和状态寄存器。

    数据寄存器:存放主机要输出到外设数据,或者外设要输入回主机的数据。

    控制寄存器:这个寄存器中存储的内容可以直接反映某一个外设具体要做什么动作,如键盘灯亮灭。

    状态寄存器:反映了当前外设状态,比如说这个外设是否处于忙碌状态,是否损坏灯。CPU可以根据状态寄存器内部的标志位判断。

    1. I/O控制方式

    有以下代码:

    了解这三个寄存器大致功能后CPU在处理scanf("&C",&i)这段代码时,CPU会先通过控制总线向I/O接口发出读命令,同时可以通过地址总线来指明要读的是哪个设备,地址总线还有一个作用是可以用于指明此次要从这个设备读入的数据应该放在哪一个寄存器。如果当前已经输入一个字符,那判断该字符是否输入方法有以下几种:

    上面两种方式的数据流是:键盘I/O接口的数据寄存器数据总线CPU某寄存器主存(变量i的对应位置)。

    上面慢速设备用程序中断方式,向CPU发出中断请求次数较少,可以使用。但是一些快速的I/O设备,如磁盘,没准备好一个字就给CPU发送一次中断请求,会导致CPU接收到中断请求频率变高,每次接收到中断请求都会执行中断程序,CPU需要花大量的时间来处理中断服务程序,CPU利用率严重下降。

    1.1 DMA控制方式

    为了让这些快速的外部设备与主机间的数据交互更有效率,一般采用DMA控制方式:

    DMA控制

    这是一种三总线结构,上面的DMA总线连接了DMA接口,这个DMA接口是专门由于管理高速的I/O设备。这里的DMA接口,即DMA控制器,也是一种特殊的I/O控制器。

    DMA控制方式:主存与高速I/O设备之间有一条直接数据通路(DMA总线)。CPU向DMA接口发出"读/写"命令,并指明主存地址、磁盘地址、读写数据量等参数。当CPU想要往磁盘读写数据时,可以通过I/O总线指明此次是要进行读写命令,如果是读命令CPU还会指明应该要把数据读到主存哪个位置,另外也要指明此时要读的数据在磁盘中的位置,最后还要指明此次要读的数据量,指明之后CPU就可以去执行其他任务。

    DMA控制器自动控制磁盘与主存的数据读写,每完成一整块数据读写(如1KB为一整块),才向CPU发出一次中断请求。

    DMA方式

    DMA控制器与主存每次传送1个字。当传送完一整块数据后才向CPU发出中断请求。

    因此引入DMA方式,如果此时有个某个程序需要进行数据读写,那么CPU会通过I/O指令向DMA接口,指明此次要读写数据的主存地址、磁盘地址、读写数据量等参数,发出这些指令后,CPU就可以去执行其他任务。而I/O设备可以慢慢准备数据,准备好的数据会先存入DMA控制器中,每准备好一个字DMA控制器就会发出DMA请求,接着DMA控制器会占用一个存取周期,往主存对应位置写入一个字的数据。如果在这个存取周期内,CPU也想访问主存则必须等待DMA控制器写好这一个字的数据之后,CPU才可以继续往后执行访问主存。因为这里主存是被CPU和DMA控制器同时共享的。所以每次DMA往主存中写入数据时,都需要占用过一个存取周期。而一个存取周期肯定要比CPU处理一个中断程序时间短。因此DMA控制方式又比程序中转方式效率快不少。

    1.2 通道控制方式

    这种DMA控制方式已经足够满足普通用户,但是对于商用中型机、大型机可能会接上超多的I/O设备,如果都让CPU来管理,那么CPU效率还是会变低。此时要用到通道控制方式:

    通道控制方式

    通道是具有特殊功能的处理器,能对I/O设备进行统一管理。通道也是处理器的一种,可以执行一些特定的通道指令这些通道指令种类、功能通常比较单一,通过通道指令的执行就可以管理各种各样的I/O设备。由上图可以看出引入通道之后,CPU已经不会和I/O设备进行直接交互了,而是由通道通过I/O总线来管理的。

    通道控制方式2

    CPU、主存和通道可以通过总线进行连接,如果此时CPU想要操作某一个I/O设备,CPU会通过I/O指令给通道指明一个具体的任务,指明要处理的I/O设备是哪一个。另外当通道管理这些I/O设备时,应该执行的程序(通道程序)在内存种的哪个位置。接下里通道就可以根据CPU的指示去内存当中一条一条取出这些通道指令。每一条通道指令的执行都会对应给一个I/O设备发出具体的命令。所以通道在执行通道指令序列时,就是在对I/O设备进行操作,并且具体要进行什么操作可以用编程方式通过通道指令灵活进行调整。当通道执行完这一系列指令后才会向CPU发出中断请求,最后CPU在对中断请求执行相应的处理即可。因此引入通道之后,CPU对I/O设备繁杂的管理工作可以进一步得到优化。

    对于之前的DMA方式来说,只能连续读入或写出一整块数据,每传送完一整块的数据都需要CPU介入,而引入通道之后对数据的存取位置输入输出这些控制,可以通过通道指令变得灵活,只需要提前编址好通道指令程序即可。只有通道完成所有工作之后,才需要CPU介入一次。

    1.3 I/O系统基本组成

    一般来说, I/O系统由I/O软件和I/O硬件两部分构成。

    I/O硬件包括外部设备、I/O接口、I/O总线等。

    IO硬件

    I/O软件包括驱动程序、用户程序、管理程序、升级补丁等。通常采用I/O指令和通道指令实现主机和I/O设备的信息交换。

    2. 外部设备

    外部设备也称外围设备,是除了主机以外的、能直接或间接与计算机交换信息的装置。可以分为输入设备、输出设备和外存设备。

    常见设备工作原理:

    1. 键盘

      键盘是最常用的输入设备,通过它可发出命令或输入数据。每个键相当于一个开关,当按下键时,电信号连通;当松开键时,弹簧把键弹起,电信号断开。

      键盘输入信息可分为3个步骤:

      ①查出按下的是哪个键。用硬件电路确定。

      ②将该键翻译成能被主机接收的编码,如ASCII码。

      ③将编码传送给主机。需要使用到I/O接口。

    2. 鼠标

      鼠标是常用的定位输入设备,它把用户的操作与计算机屏幕上的位置信息相联系。常用的鼠标有机械式和光电式两种。

      工作原理: 当鼠标在平面上移动时,其底部传感器把运动的方向和距离检测出来,从而控制光标做相应运动。

    3. 显示器

      按显示设备所用的显示器件分类:阴极射线管(CRT) 显示器、液晶显示器(LCD)、LED显示器

      按所显示的信息内容分类:字符显示器、图形显示器、图像显示器

      性能指标:

      屏幕大小:以对角线长度表示,常用的有1229英寸等。

      分辨率:所能表示的像素个数,屏幕上的每一个光点就是一个像素,以宽、高的像素的乘积表示,例如:800×6001024×7681280×1024等。

      灰度级:灰度级是指黑白显示器中所显示的像素点的亮暗差别,在彩色显示器中则表现为颜色的不同,灰度级越多,图像层次越清楚逼真,典型的有8位(256级)、16位等。n位可以表示2n种不同的亮度或颜色。

      刷新率:光点只能保持极短的时间便会消失,为此必须在光点消失之前再重新扫描显示一遍,这个过程称为刷新。刷新频率是单位时间内扫描整个屏幕内容的次数,按照人的视觉生理,刷新频率大于30Hz时才不会感到闪烁,通常显示器刷新频率在60120Hz。

      现实存储器(VRAM):也称刷新存储器,为了不断提高刷新图像的信号,必须把一帧图像信息存储在刷新存储器中。其存储容量由图像分辨率和灰度级决定,分辨率越高,灰度级越多,刷新存储器容量越大。VRAM容量计算公式如下:

      VRAM=×

      考虑刷新率,一秒钟要往VRAM中写入60帧的数据。因此对VRAM的写入速度会有一个最低要求:

      VRAM=××

      假如一个计算机分辨率为1440×900,灰度级位数是24位彩色。那么VRAM容量是1440×900×3B3.7MB(一帧的大小即为显存的理论最小值)。如果显示器刷新率为60Hz,则VRAM带宽至少要3.7×60=222MB/S

      注:现代计算机中,显存除了作为当前显示帧的缓存,还会用于保存即将渲染的图像数据,所以一般比容量最小值大很多倍。

      如果是集成显卡计算机,通常分配一片内存作为显存。

    4. 阴极射线管(CRT)显示器

      CRT显示器主要由电子枪、偏转线圈、荫罩、高压石墨电极和荧光粉涂层及玻璃外壳5部分组成。具有可视角度大、无坏点、色彩还原度高、色度均匀、可调节的多分辨率模式、响应时间极短等且前LCD已经超过。

      阴极射线管显示器

    5. 液晶显示器(LCD)

      原理:利用液晶的电光效应,由图像信号电压直接控制薄膜晶体管,再间接控制液晶分子的光学特性来实现图像的显示。 特点:体积小、重量轻、省电、无辐射、绿色环保、画面柔、不伤眼等。

    6. LED(发光二极管)显示器

      原理:通过控制半导体发光二极管进行显示,用来显示文字、图形、图像等各种信息。

    LCD与LED是两种不同的显示技术,LCD是由液态晶体组成的显示屏,而LED则是由发光二极管组成的显示屏。与LCD相比,LED显示器在亮度、功耗、可视角度和刷新速率等方面都更具优势。

    下面重点介绍CRT(阴极射线管)显示器。按照现实内容的不同可以分为一下几种:

    还有一种常用输出设备是打印机,打印机是计算机的输出设备之一,用于将计算机处理结果打印在相关介质上。其按照印字原理不同可分为击打式打印机和非击打式打印机。

    按照打印机工作方式不同可分为:串行打印机:逐字打印、速度慢;行式打印机:逐行打印、速度快。

    打印机

    3. I/O接口

    之前介绍过I/O接口:又称I/O控制器(I/O Controller)、设备控制器,负责协调主机与外部设备之间的数据传输。

    通过之前的I/O接口交互例子

    IO控制方式简介

    可以知道I/O接口有以下作用:

    1. 数据缓冲:通过数据缓冲寄存器(DBR)达到主机和外设工作速度的匹配。CPU和外设速度差距很大,所以需要数据寄存器/数据缓冲器来充当缓冲作用。
    2. 错误或状态监测:通过状态寄存器反馈设备的各种错误、状态信息,供CPU查用
    3. 控制和定时:接收从控制总线发来的控制信号、时钟信号
    4. 数据格式转换:串转换并、 并转换串等格式转换。很多设备输入或输出数据时都是串行输出的,而CPU通过数据总线取/放数据都是并行方式传输的,因此I/O接口需要进行格式转换。
    5. 与主机和设备通信:实现主机I/O接口I/O设备之间的通信。

    3.1 接口工作原理

    根据以上作用可以对I/O接口内部做更进一步的细化:

    IO接口内部的细化

    上图主机侧是内部接口与系统总线相连,实质上是与内存、CPU相连。数据的传输方式可能是串行也可能是并行传输。

    设备侧是外部接口通过接口电缆与外设相连,外部接口的数据传输可能是串行方式,因此I/O接口需具有串/并转换功能。

    图中右边有很多个外设界面控制逻辑,也就是说这样一个I/O接口,有可能会连接多个外设。

    I/O接口工作步骤:

    1. 发命令:发送命令字到I/O控制寄存器,向设备发送命令(需要驱动程序的协助)

      CPU连接在主机侧,外设连接在设备侧。CPU如果要操控打印机完成打印任务,首先CPU需要把打印机所对应的命令输入到控制寄存器当中。由于命令字千差万别,因此通常需要驱动程序协助。

    2. 读命令:从状态寄存器读取状态字,获得设备或I/O控制器的状态信息

      CPU从状态寄存器中读取状态字,同这种方式确认设备是否就绪,或者工作是否完成。

    3. /写数据:从数据缓冲寄存器发送或读取数据,完成主机与外设的数据交换。

      接下来CPU需要通过数据总线,往数据缓冲寄存器中写入想要打印的数据,之后在控制逻辑的控制下将这些要打印的数据逐个输出到打印机当中。打印机完成工作后就可以给I/O接口一个状态的反馈,当I/O接口检测到设备工作完成后就会修改状态寄存器当中相应的比特位,这样CPU就可以通过状态寄存器的标志位得知打印机打印完成。

      这里的CPU检查方式就是之前提到过的三种。

    上图状态寄存器和控制寄存器写在一起原因是控制寄存器、状态寄存器在使用时间上是错开的,因此有的I/O接口中可将二者合二为一。即当CPU要控制一个设备进行输入或者输出时,一定是CPU先向设备发出一个命令,将这个命令信息放到控制寄存器当中,之后当I/O控制逻辑取出这条命令后这个控制寄存器就空闲了,接着就没有必要将命令字一直存放控制寄存器中。另一方面I/O控制逻辑启动设备工作之后,需要随时给CPU反馈工作状态,因此可以将设备的状态信息和控制指令存放在一个寄存器中。

    注意:I/O控制器中的各种寄存器称为I/O端口。比如数据缓冲寄存器可以称为数据端口,状态/控制寄存器可以称为状态/控制端口。因此CPU在对端口数据进行读写时需要指明要读写的是哪个端口的信息,这就是地址线的作用,CPU会通过地址线来指明要往哪个寄存器中读写数据。

    I/O总线包括数据总线、地址总线和控制总线。地址总线是指明CPU要读写数据的端口是哪个。控制总线发出读写命令,还会用于给CPU反馈中断请求信号。数据总线CPU要输出或者从外设输入的数据都会通过数据总线传送放到数据缓冲寄存器当中,还会用于传输状态/命令字相关的信息,最后数据总线还会用于传输中断类信号。

    上面的I/O接口可以接入多个设备,CPU对设备确实方式是可以对每个设备对应一组寄存器,操作不同的寄存器就是在操作不同的设备。

    3.2 接口与端口

    接口与端口之间的关系如下:

    接口与端口

    接口包括端口和控制逻辑,其中端口又包含数据端口(用于读写)、控制端口(用于写)和状态端口(用于读)。

    由于接口内部有多个端口多个寄存器,为了表明CPU要访问的是哪个寄存器,因此需要给这些寄存器进行编址。编址方式有两种:

    3.3 I/O接口的类型

    按数据传送方式可分为:并行接口、串行接口。

    注:这里所说的数据传送方式指的是外设和接口一侧的传送方式,而在主机和接口一侧,数据总是并行传送的。接口要完成数据格式转换。

    按主机访问I/O设备的控制方式可分为:

    按功能选择的灵活性可分为:可编程接口、不可编程接口

    4. I/O方式

    之前介绍过I/O控制方式其控制方式三种:程序查询方式、程序中断方式和DMA方式。下面会详细讲述每一种方式的具体实现与执行原理。

    4.1 程序查询方式

    结合x86架构中的I/O指令演示执行过程。用到的x86I/O命令如下:

    指令格式功能
    IN Rd, RsI/O端口Rs的数据输入到CPU寄存器Rd
    OUT Rd, Rs把CPU寄存器Rs的数据输出到I/O端口Rd

    程序查询方式具体执行

    由上图可以模拟打印3个字符。假设这三个字符存放在主存中,需要先从主存里读出这三个字符。之后通过OUT指令CPU就会通过地址线指明此时要输出的端口是Rn+1再通过控制线指明此次是对这个I/O端口进行写操作,之后要写的命令字数据只需要通过数据传送即可。所以当前的OUT指令会保存再I/O控制器中,通过控制总线传送给外部设备,此时外部设备会反馈一个状态信息,这个状态信息会通过I/O控制器放到状态寄存器中。由采用程序查询方式,所以CPU会一直检查状态寄存器,而CPU检查状态是公告IN指令实现的。最后三个字符充分上述操作,打印完毕后CPU需要向控制寄存器发送停机命令,之后在驱动程序帮助下I/O控制器会将停机信号传给外部设备。

    程序查询方式流程图

    这种方式优点:接口设计简单、设备量少。 缺点:CPU在信息传送过程中要花费很多时间用于查询和等待,而且在一段时间内只能和一台外设交换信息,效率大大降低。

    例题:在程序查询方式的输入/输出系统中,假设不考虑处理时间,每一个查询操作需要100个时钟周期,CPU的时钟频率为50MHz。现有鼠标和硬盘两个设备,而且CPU必须每秒对鼠标进行30次查询,硬盘以32位字长为单位传输数据,即每32位被CPU查询一次,传输率为2×220B/s。求CPU对这两个设备查询所花费的时间比率,由此可得出什么结论?

    根据上面例题可以知道这种程序查询方式也可以采用这种定时查询,在保证数据不丢失的情况下,每隔一段时间CPU就查询一次I/O状态。查询的间隔内CPU可以执行其他程序。

    而之前所说的CPU会一直检查状态寄存器方式称为独占查询,这种独占查询就意味着CPU会花100时间等待I/O的完成。

    4.2 程序中断方式

    程序中断是指在计算机执行现行程序的过程中,出现某些急需处理的异常情况或特殊请求,CPU暂时中止现行程序,而转去对这些异常情况或特殊请求进行处理,在处理完毕后CPU又自动返回到现行程序的断点处,继续执行原程序。

    CPU响应处理中断基本流程是:

    1. 中断请求

      中断源(鼠标、键盘等外设)向CPU发送中断请求信号。CPU在每个指令周期的末位都是例行检查是否有中断请求。

    2. 中断响应

      响应中断的条件。如果检测到中断CPU会响应中断请求,首先会判断当前CPU自己的状态是否是可以响应中断的。如执行关中断指令后CPU就不会响应中断请求信号。

      中断判优:多个中断源同时提出请求时通过中断判优逻辑响应一个中断源。如果CPU当前可以相应中断,就需要中断判优,即同一时刻如果有多个外设发出中断信号,CPU会判断执行中断信号的顺序。

    3. 中断处理

      中断隐指令。将CPU的执行流PC转移到正确的中断服务程序的位置。

      中断服务程序。修改PC值后就可以执行中断服务程序了。

    单中断

    上面介绍一个关中断指令,CPU检测当前是否处于关中断指令方法是可以将是否处于关中断状态的信息存放在PSW寄存器中,其在PSW中关中断指令的标志位是IF,当IF=1表示开中断(允许处理中断信号);当IF=0时表示关中断(不允许处理中断信号)。

    所以如果当前指令的PSW中IF=0,则当前指令是原子操作,即一次性完成,不处理任何外部中断信号。在该指令完成后需要执行开中断指令。所以被关中断和开中断包裹的程序代码再执行过程中不会处理外部中断信号。但是也有一些优先级很高的中断信号必须被响应,即非屏蔽中断信号(如掉电)。而大多数中断信号都是可屏蔽中断信号。下面如果没有特殊说明中断信号默认为可屏蔽中断。

    如果此时CPU处于开中断状态,当检测到一个中断请求信号时判断这个中断请求信号是哪个设备发出的方法是可以设置一个中断请求标记。

    中断请求标记寄存器

    这个中断请求标记寄存器是由一个一个触发器组成的。每个触发器记录一个二进制0/1,当某一个I/O设备所对应的触发器比特位是1时,就意味着此时有来自于这个I/O设备的中断请求需要处理。对于外部设备中断,CPU是在统一的时刻即每条指令执行阶段结束前向接口发出中断查询信号,以获取I/O的中断请求,也就是说,CPU响应中断的时间是在每条指令执行阶段的结束时刻(中断周期)。

    CPU响应中断源必须满足三个条件:中断源有中断请求、CPU允许中断即开中断、一条指令执行完毕,且没有更紧迫的任务。

    如果此时有多个外部设备发出中断信号,此时就需要中断判优操作。中断判优既可以用硬件实现,也可用软件实现:

    上面讲了如何判断优先级,而关于优先级设置定义如下:

    1. 硬件故障中断属于最高级(如掉电),其次是软件中断(如用户程序发起系统调用)
    2. 非屏蔽中断优于可屏蔽中断
    3. DMA请求优于I/O设备传送的中断请求
    4. 高速设备优于低速设备,因为高速设备中断请求响应越慢,越单独高速外设的执行效率。
    5. 输入设备优于输出设备
    6. 实时设备(反馈要及时的设备)优于普通设备。

    上面对解决优先级问题后,还需要找到与中断信号相对应的中断服务程序去执行。也就是要找到中断服务程序的入口地址。即进入中断服务程序的方法是把该程序第一条指令的地址放入PC。之后处理完中断程序后,需要将PC的值恢复到执行之前指向的位置。所以在执行中断程序之前还需要保留PC的值。

    保存PC值的工作可以交给中断隐指令。中断隐指令是保存原程序的PC值,并让PC指向中断服务程序的第一条指令。

    中断隐指令具体任务:

    1. 关中断。在中断服务程序中,为了保护中断现场(即CPU主要寄存器中的内容)期间不被新的中断所打断,必须关中断,从而保证被中断的程序在中断服务程序执行完毕之后能接着正确地执行下去。

    2. 保存断点。为了保证在中断服务程序执行完毕后能正确地返回到原来的程序,必须将原来程序的断点(即程序计数器(PC)值的内容)保存起来。通常来说PC的值可以放到堆栈中,也可以存入指定的单元。

    3. 引出中断服务程序。引出中断服务程序的实质就是取出中断服务程序的入口地址并传送给程序计数器(PC)。

      可以用两种方式确定中断程序入口地址:

      • 软件查询法

      • 硬件向量法

        首先可以给每个中断请求信号进行编号。

        硬件向量法

        如上图12H地址对应的主存单元内容包含了一个无条件转移指令JMP。这个JMP指令指明了当前中断请求所对应的中断服务程序入口地址。把指向中断入口起始地址,即JMP后面的值为中断向量。

        整体工作过程是先线通过硬件排队器实现中断判优,中断判优会导致只有一个中断信号所对应的输出线会输出1,之后引入中断向量地址形成部件,生成向量地址。

        中断向量地址形成部件

        上面向量地址还有一个别名叫中断类型号。用这种向量地址指向中断向量(入口地址)方式是因为,如果当某个入口地址发生改变只需要修改向量地址指向的中断向量值即可,不用修改硬件电路。

    这里的中断隐指令其实并不是一条指令,指的是一系列的任务,而不是某一条指令。这些一系列的请求都是CPU检测到中断信号后一定会完成的指令。

    现在找到中断程序入口地址后会执行中断程序。中断程序主要任务是:

    1. 保存原来程序的运行环境

      保存通用寄存器和状态寄存器的内容(如:保存ACC寄存器的值),以便返回原程序后可以恢复CPU环境。可使用堆栈,也可以使用特定存储单元。

    2. 中断服务(设备服务)

      主体部分,如通过程序控制需打印的字符代码送入打印机的缓冲存储器中(如:中断服务的过程中有可能修改ACC寄存器的值)

    3. 恢复环境

      通过出栈指令或取数指令把之前保存的信息送回寄存器中(如:把原程序算到一般的ACC值恢复原样)

    4. 中断返回

      弹出栈顶保存的程序断点信息,使PC回到源程序断点处。

    中断处理过程总结:

    中断处理过程总结

    上图关中断到开中断之间的指令不会被其他中断信号打断,知道最后执行开中断指令后才会响应中断请求信号。这种执行中断方式称为单重中断,即执行中断服务程序时不响应新的中断请求。

    多重中断

    多重中断指的是当在执行某一个中断服务程序时,这个中断服务程序执行还有可能再次被中断。所以多重中断又称中断嵌套,执行中断服务程序时可响应新的中断请求。

    实现多重中断当中断隐指令处理完保存断点和送中断向量一些列指令后,进入中断服务程序,此时在保护环境和屏蔽字后执行开中断,之后执行中断服务程序过程中就可以接受其他中断信号。最后再执行完中断服务程序后再次关中断恢复环境和屏蔽字。

    单中断与多重中断

    这里把开中断指令放在保护环境和屏蔽字后面是为了主程序在执行保护指令时不被其他外设中断信号打断造成保存失败情况。同理,恢复环境和屏蔽字原理类似。

    上图屏蔽字的全程叫做中断屏蔽字。其作用是给CPU指明哪些中断信号应该先执行。本质上也是在解决请求信号优先级的问题。之前的硬件排队器作用是当收到多个中断请求时,只响应其中一个固定优先级。可以调整这个硬件排队器使,增加中断屏蔽功能,这样硬件排队器可以更加灵活地调节各种中断之间的优先级。

    中断屏蔽技术

    这种中断屏蔽技术主要用于多重中断,CPU要具备多重中断的功能,须满足下列条件:

    1. 在中断服务程序中提前设置开中断指令。
    2. 优先级别高的中断源有权中断优先级别低的中断源。

    每个中断源都有一个屏蔽触发器,1表示屏蔽该中断源的请求,0表示可以正常申请,所有屏蔽触发器组合在一起,便构成一个屏蔽字寄存器,屏蔽字寄存器的内容称为屏蔽字。如上图的MASK1

    屏蔽字设置的规律:

    1. 一般用1表示屏蔽(不处理该设备发送的中断信号),0表示正常申请。
    2. 每个中断源对应一个屏蔽字(在处理该中断源的中断服务程序时,屏蔽寄存器中的内容为该中断源对应的屏蔽字)。
    3. 屏蔽字中1越多,优先级越高。每个屏蔽字中至少有一个1(至少要能屏蔽自身的中断)。

    例题:设某机有4个中断源ABCD,其硬件排队优先次序为A>B>C>D,现要求将中断处理次序改为D>A>C>B

    (1)写出每个中断源对应的屏蔽字。

    中断屏蔽字

    由于A中断源只能被D中断,所以D屏蔽字0,以此类推中断源A的屏蔽字为1110,中断源B的屏蔽字为0100,中断源C的屏蔽字为0110,中断源D的屏蔽字为1111

    (2)按下图所示的时间轴给出的4个中断源的请求时刻,画出CPU执行程序的轨迹。设每个中断源的中断服务程序时间均为20us

    中断程序

    B在执行5ns后被D中断;之后运行20ns到30位置,此时D的中断程序已经执行完毕。之后再回到B运行5ns后又被A打断;A程序运行20ns后到55;之后再回到B运行5ns后被C打断;C执行20ns后回到B,直到B程序执行完毕。

    中断程序2

    程序中断

    程序中断方式深入探讨

    当CPU在运行某个程序时,此程序需要用到用到外部设备输入。CPU会通过I/O指令向外部设备发送启动输入的命令,之后外部设备就可以准备CPU想要的数据和信息。在外部设备准备数据的过程总,CPU可以继续执行之前的程序。当I/O设备完成工作后会给CPU发送一个中断请求信号,假设之前CPU运行的指令地址是K,在K指令运行周期末尾检测到中断信号,接下来要对中断信号进行处理。当CPU处理完中断信号后要返回到K+1那条指令。当CPU取走外部设备第一个数据后,可以继续给外部设备发送I/O指令,之后重复上述操作。

    程序中断方式深入探讨2

    例题:假定CPU主频为50MHz,CPI(一个指令需要时钟周期数)为4。设备D采用异步串行通信方式向主机传送7位ASCII字符,通信规程中有1位奇校验位和1位停止位,从D接收启动命令到字符送入I/O端口需要0.5ms。请回答下列问题,要求说明理由。

    设备D采用中断方式进行输入/输出,示意图如下:

    程序中断方式例题

    I/O端口每收到一个字符申请一次中断,中断响应需10个时钟周期,中断服务程序共有20条指令,其中第15条指令启动D工作。

    1. 若CPU需从D读取1000个字符,则完成这一任务所需时间大约是多少个时钟周期?

      主频50MHz,时钟周期为150MHz=20ns

      0.5ms对应时钟周期数为0.5ms20ns=25000

      传送1个字符需要的时钟周期数为25000+10+15×4=25070

      传送1000个字符需要的时钟周期数为25070×1000=25070000

    2. CPU用于完成1000个字符这一任务的时间大约是多少个时钟周期?

      CPU用于该任务的时间大约为1000×(10+20×4)=9×104个时钟周期

    3. 在中断响应阶段CPU进行了哪些操作?

      中断指令:关中断、保存断点(PC)、引出中断服务程序

    4.3 DMA控制方式

    DMA控制器通常是以块为单位进行读写的设备,如磁盘。

    DMA控制器

    假设现在CPU要从磁盘中读入一整块的数据,采用DMA控制方式,CPU可以向DMA控制器指明要输入还是输出操作;要传送多少个数据;数据在主存、外设中的地址。接着由于数据的输入是要把磁盘一整块数据放入主存中,所以CPU需要给DMA控制器指明存放地址,此外CPU还要指明这些数据在磁盘中哪个位置。当CPU给DMA控制器发送完这些参数后,假设要输入的这一整块在磁盘中只占5个字。接着磁盘数据是一个字一个字发送给DMA控制器的,所以DMA控制器中要有一个数据缓冲寄存器,用来接受磁盘送来的一个字的数据。每收到一个字之后DMA控制器就可以根据里面保存的主存读写地址,把这整个字的数据内容通过系统总线传送给主存。

    DMA控制器执行

    接着对DMA控制器传送数据过程进行细化:

    在对DMA控制器内部结构进行细化:

    DMA控制器细化

    控制/状态逻辑:由控制和时序电路及状态标志组成,用于指定传送方向,修改传送参数,并对DMA请求信号和CPU响应信号进行协调和同步。

    DMA请求触发器:每当I/O设备准备好数据后给出一个控制信号,使DMA请求触发器置位。具体工作原理是如果设备输入完一整个字的数据后,会通过总线将DMA请求触发器改为1,表示已经完成一个字的输入了。之后控制/状态逻辑会受到一个高电平信号,于是控制电路就可以接着把数据缓冲寄存器中的数据放入主存中。

    主存地址计数器:简称AR,存放要交换数据的主存地址。

    传送长度寄存器:简称WC,用来记录传送数据的长度,计数溢出时,数据即传送完毕,自动发中断请求信号。

    数据缓冲寄存器:用于暂存每次传送的数据。

    中断机构:当一个数据块传送完毕后触发中断机构,向CPU提出中断请求。DMA控制器完成一整块的数据传输之后,需要给CPU一个反馈,因此需要有一个中断机构发出中断请求信号。中断机构右侧连接了传送长度计数器,当传送长度计数器溢出后会给中断机构发送溢出信号。

    注:在DMA传送过程中,DMA控制器将接管CPU的地址总线、数据总线和控制总线,CPU的主存控制信号被禁止使用。而当DMA传送结束后,将恢复CPU的一切权利并开始执行其操作。

    DMA传送过程

    相比于之前的程序中断方式来说,程序中断方式每一个字的传送都需要CPU进行处理。但是DMA控制方式意味着,会由DMA控制着传送完一整块的数据之后再通过CPU进行处理。DMA传送过程流程图如下:

    DMA传送过程流程图

    上面讲述的方式DMA控制器需要经过CPU发送的信号来确定能不能使用系统总线,所以不会发生主存同时访问的问题。但是采用三总线结构:

    三总线连接方式

    可以看到主存和DMA控制器之间会专门用一个DMA总线进行交互,CPU和主存之间会专门用一根主存总线进行交互。在这种情况下DMA总线想要访问主存,就不需要通过CPU决定。所以这种三总线方式会出现CPU和DMA控制器同时访问主存的问题。如果这个主存不是双端口的主存,同一时刻只能支持一个访问请求,此时就产生访问问题。可以用以下三种方案解决CPU与DMA访存冲突问题:

    主存和DMA接口之间有一条直接数据通路。由于DMA方式传送数据不需要经过CPU,因此不必中断现行程序,I/O与主机并行工作,程序和传送并行工作。

    DMA方式具有下列特点:

    1. 它使主存与CPU的固定联系脱钩,主存既可被CPU访问,又可被外设访问。
    2. 在数据块传送时,主存地址的确定、传送数据的计数等都由硬件电路直接实现。
    3. 主存中要开辟专用缓冲区,及时供给和接收外设的数据。
    4. DMA传送速度快,CPU和外设并行工作,提高了系统效率。
    5. DMA在传送开始前要通过程序进行预处理,结束后要通过中断方式进行后处理。

    DMA控制器方式与中断方式对比

     中断DMA
    数据传送需要通过程序控制完成数据传输
    每次中断都会涉及到程序切换并且需要保存恢复环境
    由硬件控制数据传输的过程
    CPU只需进行预处理和后处理
    中断请求传送数据后处理
    响应指令执行周期结束后响应中断每个机器周期结束均可,总线空闲时即可响应DMA请求
    场景CPU控制,低速设备DMA控制器控制,高速设备和块设备
    优先级优先级低于DMA优先级高于中断
    异常处理能处理异常事件仅传送数据