体系结构笔记——流水线相关与冲突
五段流水线
这里介绍和分析的流水线是一个五段的精简指令集(RISC)流水线,即每一个程序指令的执行都分为五段来执行(一般情况下每个阶段(周期)占用一个时钟周期)。
阶段划分
取指周期(IF)
这一阶段是将PC(程序计数器指向当前运行指令的下一条指令)中对应地址的指令取出并放入指令寄存器(IR)中,并将PC加四指向下一条要运行的指令。(这里的一条指令占4个字节)
译码与读数周期(ID)
这一阶段是将之前获取到的指令进行译码,同时在指令中可能还有数据,比如指向不同的寄存器,在MIPS指令架构下寄存器共有32个,以一个五位的数据来表示(0~31),在译码的过程中,通过这一编码来获取对应的寄存器中的数据,这一阶段的访存是对通用寄存器组的访问。
计算与执行周期(EX)
在这一阶段是对之前获取的数据进行运算处理,但是不同的指令中含有的数据类型不同,比如有的指令中含有的是寄存器类型的数据,有的含有的是立即数。在这一阶段中主要的操作部件是ALU运算器。根据指令类型与数据类型有以下分类。
存储器访存
可能是寄存器的寻址,或者是寄存器与偏移量的相对寻址,这时候可能需要将有关的立即数进行符号扩展或无符号扩展,使得其与寄存器中的数据位数相同,再交由ALU进行加运算产生有效地址。
寄存器-寄存器
这一类型的指令中数据来源于寄存器,在上一阶段中已近完成了对数据的读取,在这一周期中只要根据指令对应的操作进行运算即可。
寄存器-立即数
这一类型的指令数据分别来自寄存器与立即数,这里的立即数可能会需要进行位扩展,之后再将处理好的数据放到ALU中运算。
分支指令
这一指令的功能是进行跳转,在跳转之前要进行条件判断(算术与逻辑操作由ALU执行),之后还要运算跳转处的地址,使用当前的PC值与目标处的标记地址进行运算(PC加上偏移量)。
访存与分支跳转(MEM)
这一阶段是为处理访存指令与分支指令设计的,对于访存指令假设是读指令Load,就是将之前运算出的数据地址作为访存地址,将对应的数据取出,而若是存指令Store,就是把相应的数据写到对应的内存单元中。而如果是分支指令,通过前一周期处理的数据来判断其是否跳转,如果跳转就将新的地址写到PC中。
写回周期(WB)
这个周期主要是处理运算结果的,对于运算指令是将其产生的运算结果写入通用寄存器组中,对于访存指令是将访存的数据结果存入通用寄存器中。
对于不同的指令其使用的阶段与周期数是不同的,比如有的指令不需要访存与跳转那就可以不执行MEM段。
相关与冲突
相关
相关的定义是针对指令的,即两条指令之间存在的依赖关系。有三种类型的相关:数据相关、名相关、控制相关。
数据相关(先写后读)
对于顺序执行的两条指令之间如果存在下一条指令使用上一条指令的数据即为相关,数据相关具有传递性,当后一条指令j与这条指令之前的指令k相关,而指令k又与上面的指令i相关,这反映了数据的流动关系。
对于数据相关,必须要保证对应数据流动的顺序,指令必须按照其数据的流动顺序来执行。相关即后面的指令(直接或间接的)使用前面指令的结果。
名相关
名是指指令访问的寄存器或存储单元的名称,如果两条指令使用相同的名,有数据流动(直接或间接)就是上面的数据相关,如果不存在数据相关即使这里的名相关。名相关根据指令间的关系可以有以下的分类。
反相关(先读后写)
指令间读操作在前,写操作在后,这是为保证读到的数据为未被修改的数据,所以必须保证先读后写,对指令的执行顺序有严格要求。
输出相关(先写后写)
指令间写操作的顺序,如果两条指令同时有写数据的操作并且其操作的目标对象为同相同的寄存器或者内存单元,则也要保证其运行的先后顺序,保证最终写入的数据是最后执行的指令的。
与上面的数据相关不同,真数据相关是数据先写入,之后的指令以其写入的结果来作为接下来运行的输入数据,即先写后读。
控制相关
由分支指令形成的相关,分支指令是要先进行判断之后进行跳转,所以在指令的运行顺序上有要求。类似于if-else语句中括号内的内容,运行顺序不能进行更改。
冲突
在具体的流水线中,下一条指令由于相关等原因无法在给定的时钟周期内执行时会产生流水线冲突。
结构冲突
由于硬件资源有限,有时会产生硬件资源无法满足程序并行运行的情况,这时会产生结构冲突。常常是多个指令的执行向同一硬件资源提出请求。
数据冲突
往往是由于数据相关产生的冲突,后一条指令需要使用前一条指令的执行结果而产生的冲突。
根据读写操作的不同会有以下三类的数据冲突。
先写后读(RAW)
对应真数据相关时的情况,下一条指令依赖于上一条指令的执行结果,必须先将结果写入之后再由下一条指令来读。如果先读的话读到的是旧值,不是运算的正确输入。
先写后写(WAW)
这个对应于输出相关,比如最后将要输出的值为后一条指令的执行结果,可是这条指令却先执行并写入了,之后执行了上一条指令的写入操作,对应于输出的结果而言就出现冲突了。
先读后写(WAR)
这个对应于名相关,指令在读取某一数据之前其读取的对象先被相关的指令写入了运算结果,这导致了读取的数据不是原来的数据,而是下一条指令运行的结果。
控制冲突
这一冲突与控制相关有关,分支指令在处理时往往要先处理条件判断,之后再进行跳转,然而在多指令并行执行时,当分支指令计算出跳转的地址时,并行执行的其他指令可能就是按顺序执行取的,并且已经运行了很久,这样就会出现问题,本应跳转运行,但是却取了顺序执行的指令运行。