RISC-V MCU中文社区

【分享】 E203添加浮点数方法:FPU控制逻辑

发表于 开源蜂鸟E203 2023-05-16 15:48:34
0
2738
7

报名编号:CICC2969

团队名称:火锅队

学校名称:广东工业大学

笔者参照原 E203 的代码增加了实现浮点指令的电路,因此会将原 E203 的代码与自己的思路对比着讲。

1. OITF 分配 tag 的时序

《手把手教你设计CPU——RISC-V处理器篇》讲到,E203的OITF只对长指令分配 itag。为什么呢?在长指令写回单元 longpwbck 里面,长指令的写回需要对比 itag 的值,并且 OITF 输出“不为空”信号时,才允许提交,代码见下图:


而这个 "oitf_empty" 信号是在指令进入 EXU 单元的第二个周期才会更新,因此单周期指令并不会在指令进入 EXU 的第一个周期写回,由此产生了错误。

2. FPU 设计

要实现整一个 FPU 及其控制单元,首先要确定指令周期,以及浮点运算的方式。

由于笔者首次使用 Verilog 设计修改 CPU,因此为了减少错误、方便后续修改,笔者将单精度浮点指令的全部运算都集中在了 FPU 当中。对于指令周期的设计,笔者将除了除法、开方和浮点数存取指令以外的指令都设计为单周期指令(实际中为2周期,原因在于 OITF 的原理),这也是为什么原 E203 代码的 “defines.v”文件里头将 DIV 和 SQRT 指令合并为同一类指令。但是为了简化实现单精度浮点数指令的电路,笔者将单精度浮点指令分类为两类:需要修改 fflags 寄存器的和不需要修改 fflags 寄存器的。

接下来讲解单精度浮点指令的实现方式。

首先是浮点数存取指令。笔者认为,单精度浮点数的数据位宽与整数一样,指令机器码格式一致,因此将浮点数存取指令与原 E203的整数存取指令一并实现了。但需要注意的是,浮点数的存取指令用到了整数通用寄存器,而整数通用寄存器不需要使用浮点数通用寄存器,这里的实现可以参考我之前的文章《E203添加浮点数方法:寄存器设计》

其次是单精度浮点数加减乘除、开方和乘加融合指令的运算。加减乘除法的 Verilog 代码可以去 github上面找。这里主要说下笔者的实现思路。笔者在加减乘运算上直接使用开源 Verilog代码。在除法和开方运算上,笔者参照 E203 低功耗、小面积的设计思想,使用同一条数据通路进行运算,虽然需要增加额外的控制器,但总体来说比分开实现所需要的面积小得多。在乘加融合运算上,笔者亦参照低功耗、小面积的设计思路,使用已有的加减乘法器来实现。

其他指令可以直接参照RISC-V手册来实现,在这里就不赘述了。

由于原 E203 代码中确定了将所有浮点指令都视为长指令,而上述单周期单精度浮点指令很明显不符合该假设。为了尽量少地改动原代码,方便后期代码 debug,笔者在 FPU 中为所有输入数据添加了一个寄存器,由此每一个指令的指令周期都增加了一个时钟周期。具体的实现代码如下图:


3. FPU控制器设计

确定了指令周期及指令实现方式后,就可以确定控制逻辑了。笔者参照 E203 的 ALU 中的 "exu_nice.v" 文件设计 FPU 控制器。对于 NICE 的通信接口各信号的解释,可以查阅《手把手教你设计CPU——RISC-V处理器篇》第16章。由于 RISC-V 架构规定,浮点指令不会引发任何中断,因此笔者删去了通信接口中的错误标志。另外,笔者将 _req_instr信号换成了 fpu_info 信号。NICE 中还设置了与 ICB 总线通信的信号,由于 FPU 不需要与 ICB通信,因此删去了所有以 “icb”开头命名的信号。

需要注意的是,由于官方例程的 NICE 处理器为4级流水线,因此 NICE 控制器的 fifo 深度为 4 。而笔者所设计的 FPU 为单级流水线,因此在 FPU 控制器中将 fifo 的深度设为1,并且将 "CUT_READY" 配置成 0。笔者的 FPU 控制器中的 fifo 配置如下图所示:

最终 FPU、 FPU 控制器和长指令写回模块之间的连接如下图所示:

FPU, ALU 和 CSR 之间的连接如下图所示:


4. 后期改进

为了加快浮点运算,可以在译码时就区分浮点指令的单周期指令和长指令,在派遣和 OITF模块中识别浮点长指令信号并且派发 itag,而单周期浮点指令可以在单周期内被执行,无需派发 itag。

以上就是本帖内容!

喜欢7
用户评论
Lalaland

Lalaland 实名认证

懒的都不写签名

积分
问答
粉丝
关注
  • RV-STAR 开发板
  • RISC-V处理器设计系列课程
  • 培养RISC-V大学土壤 共建RISC-V教育生态
RV-STAR 开发板