流水线数据相关指的是在流水线中执行的几条指令中,一条指令依赖于前面指令的执行结果。
由于流水线只能在流水线译码阶段读寄存器、回写阶段写寄存器,所以流水线存在以下三种相关情况
1.相邻指令之间存在数据相关 -译码、执行阶段存在数据相关
ori $1, $0, 0x1100
ori $2, $1, 0x0020
第一条ori指令将在回写阶段时钟上升沿写入寄存器$1
第二条ori指令将在译码阶段取$1的值,但此时第一条ori还处于执行阶段,所以得到的$1必然不是第一条ori写入的值,第二条按照此时的值计算,必然会出错。
2.相隔1条指令间存在数据相关 -译码、访存阶段存在数据相关
3.相隔2条指令间存在数据相关 -译码、回写阶段存在数据相关
其中相隔两条指令间存在数据相关的问题已经在Regfile模块解决,在Regfile模块判断读寄存器与写寄存器地址是否相同,若相同则直接赋值即可处理此问题
对于其他两种情况有三个解决方法
1.插入暂停周期:当检测到相关时,在流水线中插入一些暂停周期
2.编译器调度:编译器检查到相关后,可以改变指令的执行顺序
3.数据前推:将计算结果从其产生出直接送到其他指令需要处或需要的功能单元处,避免流水线暂停
注意:数据前推有一个前提条件,新的寄存器的值可以在执行阶段计算出来,如果是加载指令,那么就不满足这个前提,因为加载指令在访存阶段才能获得最终结果
OpenMIPS采用的是第三种数据前推的方法
主要是将执行阶段的结果、访存阶段的结果前推到译码阶段,参与译码阶段选择运算源操作数到过程。
MIPS32指令集架构中定义的逻辑操作指令有8条: and、andi、or、ori、xor、xori、nor、lui,其中 ori指令已经实现。
MIPS32指令集架构中定义的移位操作指令有6条: sll、sllv、sra、srav、srl、srlv。
MIPS32指令集架构中定义的空指令有2条: nop、ssnop。
其中 ssnop是一种特殊类型的空操作,在每个周期发射多条指令的CPU中,使用ssnop指令可以确保单独占用一个发射周期。OpenMIPS 设计为标量处理器,也就是每个周期发射一条指令,所以ssnop 的作用与nop相同,可以按照nop指令的处理方式来处理ssnop指令。
还有sync、pref这两条指令,其中sync指令用于保证加载、存储操作的顺序,但对于OpenMIPS而言,它是严格按照指令顺序执行的,加载、存储操作也是按照操作顺序进行的,所以可以将sync指令当做nop指令处理;pref指令用于缓存预取,OpenMIPS未实现缓存,所以也将该指令当做nop指令处理。
这四个指令的指令码都为SPECIAL(000000)
(1)add指令 --逻辑“与”运算
用法:and rd, rs,rt
作用:rd<-rs AND rt
(2)or指令 --逻辑“或”运算
用法:or rd, rs,rt
作用:rd <- rs OR rt
(3)xor指令 --异或运算
用法:xor rd, rs,rt
作用:rd <- rs XOR rt
(4)nor指令 --或非运算。
用法:xnor rd, rs,rt
作用:rd <- rs NOR rt
(1)andi指令 --逻辑“与”运算。
用法:xnor rd, rs,rt
作用:rd <- rs NOR rt
(2)xori指令 --“异或”运算
用法:ori rt, rs,imm
作用:rt <- rs XORI zero_extended(imm)
(1)xori指令 --“异或”运算
用法:lui rt,imm
作用:rt <- imm || 0^16
将指令中的16bit立即数保存到地址为rt的通用寄存器的高16位,低16位用0填充
(1)sll指令 --逻辑左移
用法:sll rd,rt,sa
作用:rd <- rt << sa(logic)
rt的值向左移位sa位,空出来的位置用0填充,结果保存到地址为rd的通用寄存器中
(2)srl指令 --逻辑右移
用法:srl rd,rt,sa
作用:rd <- rt >> sa(logic)
rt的值向右移位sa位,空出来的位置用0填充,结果保存到地址为rd的通用寄存器中
(3)sra指令 --算术右移
用法:sra rd,rt,sa
作用:rd <- rt >> sa(arithmetic)
rt的值向右移位sa位,空出来的位置用rt[31]的值填充,结果保存到地址为rd的通用寄存器中
(4)sllv指令 --逻辑左移
用法:sllv rd,rt,rs
作用:rd <- rt << rs[4:0]
rt的值向左移位rs[4:0]位,空出来的位置用0填充,结果保存到地址为rd的通用寄存器中
(5)srlv指令 --逻辑右移
用法:srlv rd,rt,rs
作用:rd <- rt >> rs[4:0]
rt的值向右移位rs[4:0]位,空出来的位置用0填充,结果保存到地址为rd的通用寄存器中
(6)srav指令 --算术右移
用法:srav rd,rt,rs
作用:rd <- rt >> rs[4:0]
t的值向右移位rs[4:0]位,空出来的位置用rt[31]填充,结果保存到地址为rd的通用寄存器中
空指令
为了实现逻辑、移位操作与空指令(其中 nop、ssnop不用特意实现,可以认为是特殊的逻辑左移指令sll),只需要修改OpenMIPS 的如下两个模块。
确定指令种类
根据上述指令的指令码(0~5位)和功能码(26~31位)在译码阶段确定指令
我们在本章学到了逻辑、移位操作和空指令的实现以及流水线数据相关,其实流水线还有控制相关、结构相关等,这个要继续学习下去才可以解决,一起加油吧!
其实到了本章开始可以不用手打代码了,可以直接看书配套的文件代码。当然打肯定更好可以记住,并且修bug也是一个学习的过程。