报名编号:CICC1907
团队名称:Hollow-SEKIRO-ARCAEA
学校名称:东南大学
指导老师:刘昊
团队成员:申烁、徐轶凡、林昊
这是我们第十篇分享文章。
为了完成F拓展,我们计划在ALU内添加一个专用于计算单精度浮点数的FPU单元。
即需要实现26条F指令:
以下部分指令返回地址是给整数寄存器,红色加粗表示,在模块中添加一个1bit信号e203_exu_fpu_result2which_reg区分
flw 取字
fsw 存字
fmadd.s rd=rs1rs2+rs3 融合乘加
fmsub.s rd= rs1rs2-rs3 融合乘加取反
fnmsub.s rd= -(rs1rs2-rs3) 融合乘减
fnmadd.s rd= -(rs1rs2-rs3) 融合乘减取反
fadd.s 加
fsub.s 减,加减可以用一个ip
fmul.s 乘
fdiv.s 除
fsqrt.s 开方
fsgnj.s 从rs1中读取除了符号位以外的所有位,符号位是rs2的
fsgnjn.s 符号位是rs2取反
fsgnjx.s 符号位是rs1的符号位和rs2的符号位进行XOR运算
fmin.s 最小
fmax.s 最大
fcvt.w.s 将浮点寄存器rs1中的浮点数转换为一个有符号的32位的整数
fcvt.wu.s 转成无符号的整数
fcvt.s.w 整数转浮点
fcvt.s.wu 无符号整数转浮点
feq.s 相等
flt.s 小于 less then
fle.s 小于等于 less then or equal
fclass.s 判断rs1类型,将掩码写入整数寄存器rd
这个掩码的格式如下图。如果具有该属性则将rd中的对应位置1, 否则置零(最终rd中只有1bit为1,其他位都为0)
fmv.w.x 将浮点寄存器rs1中的单精度浮点值,传给整数reg
fmv.x.w 将整数传给浮点reg(注意这两条不要改变bit值,且保留NaN)
为了节省结果的扇入,把相似计算的指令用一个模块实现,最后多选输出。
e203_exu_fpu_madd_nmadd 实现指令fmadd.s(rd=rs1rs2+rs3),fnmadd.s(rd= -(rs1rs2-rs3))
e203_exu_fpu_msub_nmsub 实现指令fmsub.s(rd= rs1rs2-rs3),fnmsub.s(rd= -(rs1rs2-rs3))
e203_exu_fpu_add_sub 实现指令fadd.s 和 fsub.s
e203_exu_fpu_mul 实现指令fmul.s
e203_exu_fpu_div 实现指令fdiv.s
e203_exu_fpu_sqrt 实现指令fsqrt.s
e203_exu_fpu_fsgnj_n_x 实现指令fsgnj.s fsgnjn.s fsgnjx.s
e203_exu_fpu_max_min_cpr 实现指令fmax.s fmin.s feq.s flt.s fle.s
e203_exu_fpu_ws_wus 实现指令fcvt.w.s fcvt.wu.s
e203_exu_fpu_sw_swu 实现指令fcvt.s.w fcvt.s.wu
e203_exu_fpu_fclass 实现指令fclass.s
e203_exu_fpu_fmvwx_fmvxw 实现指令fmv.w.x fmv.x.w
如上一节,实际上的模块数量小于26,复用一些模块使单个模块实现多种计算节省面积。
信号处理过程如下:
输入四个32bit信号:三个来自rs1,rs2,rs3的数据和一个控制信号,输入数据的握手信号;输出一个32位的计算结果及其握手信号。
计算单元将收到的三条数据和使能信号同步发给20多个模块,同时只有一个模块被时钟使能,进行计算,但结果都会保留,发给数选。计算单元还需接受和给出握手信号。在RISC v架构中每个模块(包括FPU)的握手信号都有一个i_valid、i_ready,FPU内部需要三个输入数据的握手信号、一个输出结果的握手信号。
输入数据来自解码后相应地址的寄存器,每个输入数据附有握手信号,即ready、valid。根据握手规则,输入的valid信号将输给对应的子模块(不需要的出0,用判断语句实现),需要计算的子模块再输出ready信号。该模块的多个输入信号(也有可能只有一个)的ready相与(即全1才可输入,ready置零表示在计算,无法输入)成该模块的ready信号,每个模块的ready信号通过一个数选给到FPU的ready。
输出握手信号的valid也是通过数选给到FPU的valid。(输出信号的valid由模块给出,ready由接收模块发给FPU,且一个模块只会有一个输出)。
这里有两个问题:仿真时ready是持续拉高,而在计算时没有翻转;原本IP核在完成AXI协议时,需要一个tlast信号,但例化ip时没有给出,.veo里也没有,e203似乎也不支持这个功能,就不加了)
后来发现输入数据的握手信号实际上控制输出的握手信号,即只有当输入的valid拉高后计算的数据才会输出。输入数据的计算是否进行不受握手信号影响,不管输入的valid是否有效,只要输入32位有效的数据,就会计算并产生输出。此时尽管模块的输出已经变化或产生,但此时接收模块的端口可能并不会收到握手信号的valid,也就不会让输出传过去。
模式控制信号为解码后转换成的掩码,根据26条指令有26种不同的计算模式,每个模式分配一位,当需要进行某计算模式时,该位将置一,其他位置零。
输入FPU的模式控制信号不仅决定哪个模块运行,对于有多种模式的模块,该信号还要进一步转换成控制该模块进行不同计算模式的信号。
上图的计算单元将收到的三条数据和使能信号同步发给所有子模块,同时只有一个模块被时钟使能,进行计算,但结果都会保留,发给数选。计算单元还需接受和给出握手信号。在RISC v架构中每个模块都有一个i_valid、i_ready。FPU内部需要同时给出三个输入数据的握手信号、一个输出结果的握手信号。
根据控制信号的仿真结果,如果在时钟使能有效时,同时发给所有模块,不管valid是否有效都会计算,浪费功耗。下图显示了输入valid、输入ready、时钟使能三者的关系:时钟使能决定了IP使计算还是保持,若使能无效则保持之前的结果,而不随信号变化。一旦使能则开始计算(不管输入信号是否“有效”,即valid是否拉高)。
因此输入数据信号可以设计成:不做处理地同时发给各个模块。
输出信号同其握手信号一样,经过数选给到FPU的result。有的模块可以进行多种计算,模块result只需给一个,减小数选扇入。
本文介绍的内容是为了完成基础功能:对蜂鸟E203 RISC-V内核的微架构实现进行一定优化,提高whetstone的关键之一是拓展浮点计算。