北航961计算机组成-MIPS流水线处理器

MIPS流水线处理器

一、流水线概述

以生活中的流水线为例,洗衣房洗衣服分为以下几步:1. 洗涤,2. 烘干,3. 熨整。如果每批衣服都完成以上三步才开始洗下一批衣服,会造成大量的资源浪费。如果上一批衣服在烘干的时候下一批衣服能够开始洗涤,就可以提高资源利用率。MIPS流水线CPU的思想原理正是基于这种朴素的思想。

图1 串行洗衣房
图2 并行洗衣房

同理,MIPS处理器执行指令的过程也可以分为几个逻辑独立的部分:

  1. IF:取指,PC自增
  2. ID:指令译码,读寄存器
  3. EX:运算
  4. MEM:读写数据存储器
  5. WB:写回寄存器
    流水线CPU数据通路
    为了保存指令在每个周期的中间结果,需要添加4组流水线寄存器,这样就构成了一个五级流水线CPU。上图只是流水线CPU的大致示意,细节会在后续小节具体介绍。

二、流水线数据通路及其控制

数据通路

流水线寄存器
在单周期的数据通路上插入4组流水线寄存器:

  1. IF/ID寄存器:主要存指令译码的结果,指令的各个字段
  2. ID/EX寄存器:主要存rs和rt寄存器的值,以及立即数符号扩展后的值
  3. EX/MEM寄存器:主要存ALU的计算结果
  4. MEM/WB寄存器:主要存数据存储器的输出,以及ALU的计算结果
  5. RF寄存器:可以看成是最后一级流水线寄存器,在这儿更新结果

更详细的图(存在问题):
流水线CPU
两个最重要的疑问

  1. 在同一个周期内,前面的指令写寄存器堆,后面的指令读寄存器堆?
  2. 更新PC的时候,需要在PC+4和NPC之间选择,会有什么问题?

可以保证的是,这两种情况不会影响之前的指令,只会影响后面的指令。第一个问题会造成数据冒险,第二个问题会造成控制冒险,具体见后面两节。在这节介绍数据通路时,我们暂时不管这两个问题,以免造成混乱。

一个具体的例子
下面我们以数据通路最长的lw指令为例来理一遍流水线的数据通路。
IF
IF阶段:这个阶段主要是读IM,将指令取出放入IF/ID寄存器中。这里可以看到一个现象:lw指令显然是执行 P C ← P C + 4 PC\leftarrow PC+4 PCPC+4,但是依旧会把PC+4存入IF/ID寄存器中,以便于计算NPC。这体现了一个原则:尽可能将信息往后传递,即使这条指令用不到,其他指令也有可能会用到,贸然舍弃不可取。

ID
ID阶段:在此阶段,lw指令需要从寄存器堆中读取第一个寄存器的值作为基址,并且将16位立即数符号扩展为32位立即数。同理,这一阶段还是会将所有后续可能用到的数据向后传递(第二个寄存器的值,lw用不到但是也向后传递了)。此图目前有一个问题,如果你此时发现了能想到如何改正吗,不行的话也没事,我们在WB阶段会改正这个错误。

EX
EX阶段:我们在这个阶段根据基址加偏移算出最终的数据地址,并将结果存入EX/MEM流水线寄存器中。

MEM
MEM级:根据地址从DM中取出数据并存入MEM/WB流水线寄存器中。

WB
WB级:将MEM/WB流水线寄存器中保存的数据写回寄存器堆中。需要注意的是,这里的写寄存器编号并不是当前lw指令对应的写寄存器编号,而是此时运行到ID级的指令的编号,因此需要更改一下数据通路。下图就是正确的通路。
WB
流水线的图形化表示
图形化表示
书上最常见的表示形式就是这种比较完整仔细的形式,横向是时间,也就是周期,纵向是指令。个人更倾向于使用另一种表示方法,只画一个简易的流水线图,然后在各个阶段标注正在执行的指令,这对于做题分析更有帮助。
在这里插入图片描述
在此图的基础上简化各个部分的部件,一个框加字母即可,怎么方便怎么来。

流水线控制

控制
由单周期CPU的设计可知,指令执行的过程中需要很多的控制信号来引导指令的正确执行,比如运算类型ALUOp、写寄存器信号RegWr等等。在单周期CPU中所使用的控制信号在流水线CPU中依然适用,唯一不同的是需要将控制信号和数据一起往后传递,以便于指令在执行的过程中能够一直得到对应自己的控制信号。
最简单的实现方式当然就是将控制信号一股脑地往后传递,但是因为控制信号的作用域易于区分,即一个控制信号可以明确在哪个流水级使用,所以我们可以将控制信号按照作用的流水级分组,并且在传递的过程中有选择地舍弃。

三、数据冒险:转发与阻塞

冒险一共有三种类型:

  1. 结构冒险:硬件不支持多条指令在同一时钟周期中执行,流水线的设计可以非常简单地避免结构冒险(IM和DM分开就避免了结构冒险)。另外一个结构冒险是在同一个时钟周期内前面的指令写回寄存器堆而后面的指令读寄存器堆造成的冲突,解决这个结构冒险的常见办法之一是通过前半个周期写后半个周期读实现,因此可以保证此时能够读到正确的数据。
  2. 数据冒险:数据相关,MIPS中只有RAW相关,即前面的指令是写寄存器,后面的指令是读寄存器。在前面的指令还没有来得及将结果写回寄存器的时候(WB级结束),后面的指令就需要从同一个寄存器中取数,此时就会造成数据冒险。
    数据冒险
    以上图为例,当运行到第三个周期时,sub指令需要从寄存器r1中读取操作数,但是前一条指令add并没有将结果写回r1寄存器,而是需要在第5个周期才能写回,这就造成了sub指令取出的数据是“旧”的数据,造成结果错误。而对于第四条指令or,add指令在第5个周期写寄存器,add读寄存器,这个就可以通过修改寄存器的内部结构改变,因此不会造成数据冒险(原ppt上画了红色,应该不太对)。
    但是仔细分析可以知道add指令在第3个周期的结束就已经产生了正确的运算结果并且存入了EX/MEM流水线寄存器中,而后续的4条指令真正使用到r1寄存器值的时间都在第4个周期及之后,因此理论上就可以通过将EX/MEM流水线寄存器中的结果提前“转发”(也叫旁路)——这就是解决数据冒险的办法之一。
    转发
    更精细的数据冒险类型以及判定条件:

1a. EX/MEM.RegisterRd = ID/EX.RegisterRs
1b. EX/MEM.RegisterRd = ID/EX.RegisterRt
2a. MEM/WB.RegisterRd = ID/EX.RegisterRs
2b. MEM/WB.RegisterRd = ID/EX.RegisterRt
对应1a的更具体的判定条件:
if(EX/MEM.RegWrite && EX/MEM.RegisterRd != 0 &&
EX/MEM.RegisterRd = ID/EX.RegisterRs) ForwardA = 10
对应2a的更具体的判定条件:
if(!(EX/MEM.RegWrite && EX/MEM.RegisterRd != 0 &&
EX/MEM.RegisterRd = ID/EX.RegisterRs) &&
(MEM/WB.RegWrite && MEM/WB.RegisterRd != 0 &&
MEM/WB.RegisterRd = ID/EX.RegisterRs))
2a需要先判定是否满足1a条件,因为1a结果更“新”

然而并不是所有的数据冒险都是能够通过转发解决,还有一些特殊的情况比如
数据冒险
lw指令最早在T4结束才能得到t0寄存器的正确结果,而sub指令最迟在T4开始就需要使用t0寄存器的值,因此就无法通过转发解决。此时只能使用解决数据冒险的另一个办法——阻塞。
阻塞
目前指令集中只有一种可能会造成必须要阻塞:前一条指令是lw指令,后一条指令使用lw指令的目的寄存器作为源操作数寄存器。因此可以在ID级添加冒险检测单元,检测冒险的逻辑如下:

if(ID/EX.MemRead &&
(ID/EX.ResgisterRt = IF/ID.RegisterRs ||
ID/EX.ResgisterRt = IF/ID.RegisterRt) )
stall the pipeline

完成阻塞需要做的事:1. 冻结前面的流水线寄存器PC和IF/ID(PC寄存器也可以理解成流水线寄存器),即修改其写使能信号为0,2. 清除ID/EX流水线寄存器,即修改其clr信号为1,这样就相当于在lw指令后面加了一条空指令。

四、控制冒险

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顾宁安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值