计算机组成原理基础知识-流水线

1.流水线的五大阶段:(1)取指(2)指令译码、读寄存器堆(3)执行、地址计算(4)存储器访问(5)写回

2.关于流水线的控制

流水线的控制体现在后三个阶段,前两个阶段没有需要控制的内容。对于执行、地址计算阶段,需要控制的信号是ALUOp(两位信号)和ALUSrc。对于ALUOp来说,主要实现的是对ALU control的控制,通过ALU control可以实现ALU不同的功能(R type型命令的加减乘除、load、store、beq),这个过程是通过ALUOp和输入到ALU control的信号一起来影响ALU的行为。而对于ALUSrc来说,主要实现的是对ALU的第二个操作数的控制,当ALUSrc为高的时候,第二个ALU操作数是指令的低12位符号扩展,而当其为低的时候表示的ALU的第二个操作数来自第二个寄存器的输出。

计算机组成原理基础知识-流水线_第1张图片

注意看ex阶段缓存的内容分出了两个信号,分别是alusrc、aluop分别给了mux和alu conrol单元。 

关于ALUOp信号:

ALUOp信号进行多级译码的优势在于多级控制可以减少主控单元的规模,多个小的控制单元可能潜在的减少控制单元的延迟。ALUOp由opcode操作码得到,并且ALUOp和指令中function的字段一起决定ALU的控制输入。

---------------------------------------------------------------------------------------------------------------------------------

对于存储器访问阶段,主要的控制线是Branch、MemRead、MemWrite信号。Branch信号主要实现的是pc值是否跳转的控制,将branch信号和EXE/MEM寄存器中寄存的来自ALU中的0输出位相与,得到PCSRc(这种情况主要用在一些指令跳转的情况)。对于后两个信号主要是控制存储器的读和写的行为。

写回阶段:有两个控制信号,分别是MemtoReg和Regwrite,对于前者表示的是对写回数据的选中,选择写回的数据是来在ALU还是来自存储器,对于后一个信号控制的是是否将选中的信号写回寄存器。

需要注意的是这八位信号需要和指令进行一定的对应。

此外需要注意单周期CPU的控制单元Contorl,输入为指令的低七位(也就是opcode),存储器的读写控制、寄存器文件的写的控制、ALU第二个操作数的选择控制(ALUSrc)、存储器输出的选择控制(MemtoReg,决定写入寄存器的书籍是来自存储器还是来自ALU,高为存储器,低位ALU)、跳转指令、ALUOp。

---------------------------------------------------------------------------------------------------------------------------------

3.流水线冒险

分为结构冒险、数据冒险、控制冒险。

结构冒险:硬件不支持多条指令在同一时刻执行。除此以外还有一些情况,比如流水线结构中只有一个存储器,那么可能会出现某一条指令在从存储器中器数据的时候同时另一条指令也需要对存储器进行一定操作,那么此时就会出现结构冒险。可以通过合理的设计避免结构解决,也就是说将原有的单存储器的结构(冯诺依曼模型)改变为双存储器的结构(哈佛模型)。

冯诺依曼模型是数据和指令都放在同一个存储器中,而哈佛模型是将数据和指令分开放在两个cache中。此外还需要注意冯诺伊曼的现在计算机体现结构是以运算器为核心,也就是即使一开的程序数据也需要经过运算器才能到达存储器,这种体系结构的效率会降低,现在的计算机体系结构都是以存储器为核心。(什么叫一开始的程序数据?)

数据冒险:由于一个步骤必须等待另一个步骤的完成而导致的流水线停顿叫做数据冒险,数据冒险的解决方式是前提或旁路(向内部资源添加额外的硬件以尽快找到缺少的运算项)、停顿。

--------------------------------------------------------------------------------------------------------------------------------

数据冒险需要注意以下几个方面:

(1)前递的实现是通过多选器控制(forwarding unit)来避免数据冒险的,由于在ALU计算之前需要知道ALU的输入究竟来自哪个寄存器,需要了解是否存在结构冒险的可能,因此需要将ID/EX寄存器中的rs1和rs2给到forwarding unit以判断ALU的输入,在此基础上需要的ALU的数据输入进行操作。针对ALU的两个输入,每个输入有三种可能,分别是来自寄存器堆(具体内容来自ID/EX寄存器)、来自上一个alu计算结果的前递(具体内容来自EX/MEM寄存器)、来自数据存储器或者更早的ALU计算结果的前递(来自于MEM/WB寄存器)。forwarding unit共有两组信号,每组信号两位,分别对应第一个ALU输入和第二个ALU输入。

计算机组成原理基础知识-流水线_第2张图片

 注意上面这张图表示的意思,对于id/ex的rd实际上是并不需要输入给forward unit的,后面ex/mem和mem/wb给到forward unit的实际上是rd

计算机组成原理基础知识-流水线_第3张图片

rs1、rs2、rd是什么?

rs1和rs2的分别是输入alu的两个源寄存器,而rd是计算出来的结果,这个结果需要写道rd目的寄存器中。

(2)前递并不能完全的解决数据冒险的问题,当一条指令在加载指令写入一个寄存器之后紧跟着一条指令需要读取加载指令的结果的时候(load-use指令),前递并不能解决此处冒险,流水线必须被阻塞已解决出现的冒险。

这是由于对于load指令来说,实际真正拿到数据并不是在ex阶段结束后,而是访存阶段才能拿到数据。上面分析的情况是由于在ex阶段拿到数据了,可以把上一个指令的ex阶段输出的数据作为下一个ex阶段输入的数据进行操作。但是在load、use指令中,load指令的数据只会在mem阶段以后才会得出数据,因此这种情况下同样需要插入气泡。

解决这个问题可以通过调整指令执行的顺序解决。比如多次的load、use操作过程中实际上正常情况下每次都需要插入一个气泡才能解决。但是可以重新调整执行指令的顺序来解决这个问题。比如执行三次load操作,然后再第四次执行指令阶段进行加操作,但是加操作的两个数是第一个load操作和第二个load得到的数,通过这种调度的方式避免插入气泡。

产生这种冒险的条件是:需要时加载指令;加载指令的目标寄存器和下一个指令的ID阶段的源寄存器匹配;目标寄存器的不为0。一旦这三个条件均满足,那么就需要阻塞一个周期以避免数据冒险。

数据冒险分为四种,从EX/MEM进行旁路,数据送给的寄存器是rs1和rs2时,分别为1a,1b;

也就是前一个写指令需要写的目的寄存器传递到ex/mem中,此时后一个指令又过来了,而后一个指令需要的源寄存器正好是前一个需要写入的目的寄存器中的值,,这种情况根据后一个指令是rs1需要之前的rd值还是rs2需要rd的值分为两者。

从MEM/WB进行旁路,数据送给的寄存器时rs1和rs2时,分别时2a,2b。

与上面的情况类似,只是这里旁路是从mem/wb进行旁路。

计算机组成原理基础知识-流水线_第4张图片

此外需要注意一些情况:

双重冒险,同时对x1进行写两次,第三次指令对x1进行读操作。那么实际上此时1a,2a的旁路条件均满足。此时需要注意要用的x1应该是最新的数据结果。因此需要从1a进行旁路。结论结束在出现双重冒险的时候实际上需要从1a、1b进行旁路。 

和数据冲突相关的冒险类型分为三大类,分别是:

写后读,读后写,写后写。对于读后写,出现数据冒险的情况是在乱序发射的情况,也就是为了资源的调度使得写命令被提前,这种情况下就会出现数据冲突;对于写后写的情况主要是出现在乱序完成的情况下,也就是先执行的写操作可能后完成,使得先执行的写操作覆盖了新的数据。

---------------------------------------------------------------------------------------------------------------------------------

基于此,设计冒险检测单元(hazard detection unit),其信号控制包括:

输入包括IF/ID寄存器和ID/EX寄存器单元给到冒险检测单元的信号,输出包含给到IF/ID的控制信号、给到PC的信号(前面这两组信号是为了确定当冒险发生时是否需要更新正在IF/ID中的指令和下一条指令)、给到数据控制值/全0之间的选择器的控制信号。如果冒险检测为真,那么需要停顿ID和IF的指令,具体的操作包括禁止PC寄存器的改变、禁止IF/ID寄存器的改变,同时通过数据控制值/全0之间的选择器将给到ID/EX寄存器的内容变为全0(控制值均为0的情况下,不会有寄存器或存储器被写入数据,也就是EX阶段执行的后半段流水线执行的是空指令)。

在数据冒险的基础上还存在着双重数据冒险,也就是存在三条指令,前两条指令得到的结果均是第三条指令需要的内容。在这种情况下我们需要的是较新的内容,也就是第二条指令中的内容。因此在进行旁路是需要增加条件,当既有1类冒险也有二类冒险时,需要使用1类旁路,仅在只有2类冒险时才使用二类旁路。

---------------------------------------------------------------------------------------------------------------------------------

控制冒险:由于取到的指令并不是所需要的,导致正确的指令无法在正确的时钟周期内执行。

控制冒险的解决方式是:

(1)在电路中增加硬件以保证在ID级别就可以完成寄存器的比较,但是这种方法在五级流水线中也就是遇到分支时就插一个气泡的操作,在更长的流水线操作中阻塞无法被接受(入比如超标量流水线中)。如果不是提前到译码阶段进行指令的比较的话,那么需要等到最后阶段访存才可以比较pc值,那么这种情况等待的时间会更长。

(2)预测-假设分支不发生

(3)静态分支预测:针对循环(比如for循环,是往后跳)和if(if语句是往前跳)声明的分支,对于向后的分支预测发生,而对于向前的分支预测不发生。

(4)动态分支预测:通过增加一个硬件的分支预测缓冲表来实现,表中记录了指令的地址和是否跳转下次遇到表中记录的地址时根据表中记录的跳转情况进行预测。但是这种动态的预测分支针对循环中嵌套的循环会导致在每次子一级的循环中都会预测错误,因此需要改进,将其可以进一步改进为2位预测,也就是在原有的两个状态(命中就跳转没有命中就不跳转)的基础上增加两个状态(增加跳转状态和分支不跳转的中间状态)。此外无论上面的哪种预测发生跳转时都是需要一个周期来计算跳转的地址,因此可以在分支预测缓冲表的基础上增加其他内容,也就是在家PC地址和其对于的具体操作指令,通过这种方式来避免计算跳转指令浪费的一个周期。

计算机组成原理基础知识-流水线_第5张图片

 

 一些其他的概念:

超标量流水线的概念:每个时钟周期能够并发多条独立的指令,需要额外的硬件资源。

你可能感兴趣的:(计算机组成原理,开发语言)