Rocket - core - bypass或者stall
https://mp.weixin.qq.com/s/g2oTABxX1RXp03sod87hmw
简单介绍bypass或者stall之间的差异。
1. 概述
bypass的条件与stall的条件并不相同,甚至应该互斥。即不能bypass的则stall,不stall的则bypass。前提条件是存在hazard。下面针对这两种情况进行分析。
2. bypass的判断条件
bypass的条件由id_bypass_src根据bypass_sources中定义的情况确定:
以ID/EX两个阶段的hazard为例,要bypass的情况,简单而言就是RAW,即Read After Write,即ID阶段的指令,需要EX阶段指令要回写的寄存器的值。(由于用来做bypass的数据来自于mem_reg_wdata,而mem_reg_wdata使用alu.io.out进行更新,所以EX阶段指令的rd的值必须来自于alu.io.out。)
3. stall的判断条件:以ID/EX两个阶段的hazard为例
以ID/EX两个阶段的hazard为例,stall的条件为:
忽略fpu hazard,就是data hazard去掉一些不能bypass的情况。
这里的data hazards包含RAW和WAW两种情况:
a. ex_waddr与id_raddr1/id_raddr2进行比对;
b. ex_waddr与id_waddr进行比对;
不能bypass的情况,则不是单纯的从理论上来考虑,还包括一些实现上没有bypass的情况。
首先从理论上而言,不能bypass而必须stall ID阶段的指令的原因,就是EX阶段的指令无法及时的给出所需要的数据。包括:
a. 计算需要的时间过长;
b. 读取所需要的时间过长;
从当前的实现而言,
a. mul/div/fp/rock/scie表示计算所需要的时间过长;
b. mem表示获取所需要的时间过长(在最快即dcache命中的情况下,在WB阶段才能返回数据);
那么另外的两种情况呢?为什么csr和jalr不能bypass呢?这是因为实现的原因。
4. 为什么jalr不能bypass而jal可以?
这是一个很容易联想到的问题。
首先看jal指令的情况:
其效果如下:
a. PC + imm => target address;
b. PC + 4 => rd;
jalr指令在规范中的描述如下:
其效果如下:
a. rs1 + imm => target address;
b. PC + 4 => rd;
看上去并没有太大的差异。在看二者的实现:
可以看到,虽然都使用alu做加法运算,但是jal指令使用alu计算PC + 4,而jalr使用alu计算rs1 + imm。jal指令的PC + 4后续回写到rd,而jalr指令的rs1 + imm却不会回写到rd。
所以对jalr指令,不能将alu.io.out的值用于bypass。而在bypass的实现中,只使用的是mem_reg_wdata进行bypass,其值来自于alu.io.out:
所以jalr不能用于bypass,而jal可以。CSR指令的情况也类似:
alu计算的结果要存入csr,而不是rd:
5. 小结:以ID/EX两个阶段的hazard为例
1) data hazards
使用图形表示,data hazards的情况,包括在如下的矩形中:
2) RAW和WAW
data hazards包括RAW和WAW两种情况:
3) ex_cannot_bypass
如果加上ex_cannot_bypass代表的情况,其关系图示如下:
其中:
针对RAW的情况:
a. bypass判断时,判断了RAW的情况:
b. ex_cannot_bypass从RAW中排除了一些不能bypass的情况,必须要stall;
c. RAW中剩余的情况,就是实际bypass了的情况;
针对WAW的情况:
a. WAW的全部情况都不需要bypass;
b. WAW的部分情况需要stall,如ex_ctrl.mem代表的情况。所以ex_cannot_bypass也从WAW中排除了一些情况;
4) 跳出data hazards之外
如果跳出data hazards之外,考虑与ex_cannot_bypass的关系,其关系如下图:
ex_cannot_bypass中包含了一些data hazards中不包含的情况。如果没有data hazards的限制,这些情况也会导致stall。加上了data hazards的限制之后,这些情况则不会导致stall。也就是说存在一些情况,虽然前面一条指令需要花较长时间而没有执行完成,但后一条指令却没有被stall而继续执行。在这种情况下,后一条指令先于前一条指令完成。
考虑如下指令序列:
1: load
2: nop
第1条指令属于ex_cannot_bypass的情况(ex_ctrl.mem = true),但两条指令不是data hazards(既不是RAW,也不是WAW)。不满足id_ex_hazard的条件:
所以不会导致第2条指令stall在ID阶段。而是会继续沿着流水线经过EX/MEM/WB阶段执行完毕。
因为第一条指令的信息存放在sboard中,另一部分经过io.dmem.req被dcache模块记录,dcache模块返回时会带有相关的信息,所以不影响返回结果回写寄存器。