Rocket - core - bypass相关的变量
https://mp.weixin.qq.com/s/-mb2ENHqnciGiSLXUwOOBA
简单介绍bypass相关变量的用法。
1. 概述
所谓bypass或者forward,就是把没有回写到寄存器中的数据提前传给后续的指令使用:
在当前实现中,所有的bypass都传递到后续指令的EX阶段,作为alu的两个运算数使用。
2. 用到的各个变量之后的关系
总体表格如下:
1) id_raddr
id_raddr是一个序列,包含rs1/rs2两个源参数寄存器的编号:
id_rs中存放着从寄存器中读取出来的值。
2) waddr
{ex,mem,wb}_waddr中存放的是目标寄存器(rd)的编号:
可以参考规范中的指令格式。
3) bypass_sources
bypass_sources是一个三元组序列:
三元组的定义为:
a. _1: 匹配条件之一:用于对可以进行bypass的指令进行过滤;
b. _2: 待匹配的寄存器编号:用于与id_raddr1和id_raddr2进行匹配;
c. _3: 匹配成功之后,要bypass的数据;
bypass_sources中有四个三元组:
a. 第一个三元组代表x0:(x0默认可以bypass,待匹配的寄存器编号为0,bypass的数据为0);
b. 第二个三元组:使用EX阶段指令的rd与id阶段指令的rs1/rs2进行比较,如果匹配成功使用mem_reg_wdata的值进行bypass。为什么ex阶段的匹配使用mem阶段的寄存器的值进行转发呢?因为匹配和转发并不同时发生:匹配发生在ex阶段,而转发发生在mem阶段。即转发比匹配晚一个周期。
c. 第三个三元组:将mem阶段指令的rd与id阶段指令的rs1/rs2进行比较。如果匹配成功,使用wb_reg_wdata进行转发。可以看到,这里匹配和转发也是相差一个时钟周期。这种转发是WB阶段向EX阶段转发。如果两条可以进行b中转发的指令中间添加一条nop指令,即可变为这一种转发。
d. 第四个三元组:将mem阶段指令的rd与id阶段指令的rs1/rs2进行比较。如果匹配成功,使用wb_reg_wdata进行转发。这里待转发的数据涉及内存操作。
4) id_bypass_src
id_bypass_src中记录了id_raddr1/id_raddr2分别与四个三元组逐个匹配的结果:
5) bypass_mux
bypass_mux是待转发数据的序列:
6) ex_reg_rs_bypass
ex_reg_rs_bypass中记录了id_raddr1和id_raddr2是否可以使用bypass过来的值:
其赋值如下图所示:
其中:
a. id_bypass_src(i)中记录了id_raddr1或者id_raddr2与四个三元组匹配的结果;
b. id_bypass_src(i).reduce(_||_)标识是否存在匹配成功的项,将其记入do_bypass;
c. do_bypass用于更新ex_reg_rs_bypass(i),即id_raddr1或者id_raddr2对应的项;需要注意的是,这里将匹配结果存入了流水线寄存器,在ex阶段再使用。
7) ex_reg_rs_lsb
ex_reg_rs_lsb有两种用法:
a. 用于存放bypass_sources四个三元组中匹配成功的三元组的编号(可以留意其位数的计算方法)。在实现中使用PriorityEncoder取出第一个匹配成功项的编号。
b. 用于存放从id_rs(i)中取出的从寄存器中读出的值的低位;
8) ex_reg_rs_msb
ex_reg_rs_msb用于存放从寄存器中读出值的高位。
9) ex_rs
ex_rs是Mux结构的序列,包含2个Mux:
其中:
a. 每个Mux用于生成一个alu的参数;
b. Mux从bypass的值和寄存器读取值中间进行选择;
c. Mux逻辑结构处在EX阶段,使用的是ex_reg_rs_xxx等寄存器的值;已经比这些值生成时晚了一个时钟周期;
10) alu
使用ex_rs计算出alu的两个参数,并与alu连接:
3. 匹配与转发分离
在ID阶段即可解码出指令需要使用的源参数寄存器和目标寄存器。所以在ID阶段即可与后续的EX/MEM/WB阶段进行匹配,看是否有可以转发的数据。但是即便转发过来也无法在ID阶段使用,因为ID阶段已经过去大半即将结束,所以只能在EX阶段使用。当ID阶段的指令前进到EX阶段之后,原来WB阶段的之后也已经执行完成不在流水线了。所以匹配时只需要匹配EX/MEM阶段即可,而转发时则是从MEM/WB阶段的数据进行转发,转发到EX阶段。
简单图示如下:
1) 匹配
2) 转发
总体图如下: