报名编号:CICC2969
团队名称:火锅队
学校名称:广东工业大学
笔者参照原 E203 的代码增加了实现浮点指令的电路,因此会从原 E203 的代码讲起。
1. E203 的预译码模块
E203 在IFU 中有一个预译码模块,预译码模块是直接例化 EXU 中的译码模块的,本文就把预译码模块和译码模块在本节一起讲了。在这里吐槽下:要是 E203 的预译码模块删掉那些不需要的部分多好,都不用浪费那么多面积和功耗了。
先来看下预译码模块怎么与其他模块连接的:
可以看到预译码模块只有指令输入。输出端,蓝色为与整数通用寄存器相连的端口,用于读寄存器。黄色标记的是指令相关信息,提示后面的模块抓取的模块属于哪一类运算指令,剩下的是与跳转指令有关信号。进去 minidec 里面:
可以看到,除了指令输入端口外,其他端口都被清零了。结合上一篇文章《E203添加浮点数方法:寄存器设计》,可以总结出如下的电路结构图:
图中黑色部分是原 E203 的 IFU 部分结构图,这里只拿 rs1 作为例子画了出来。图中红色部分是笔者参照原电路画出的浮点相关电路结构图。
接下来是译码模块的解释。当初笔者看到decode模块的代码时,都震撼了,因为这是所有模块中代码最长的模块。但是这部分其实是按照 RISC-V 手册编写的,因此不需要考虑复杂的逻辑组合,参照着手册一个一个指令敲就好了。
E203的译码模块将指令分为 6 个类别(算上 nice 的):alu_op, amoldst_op, bjp_op, csr_op, muldiv_op, nice_op. E203 的作者在这个模块中设计了条数据总线 dec_info,不同类别的指令使用同一条 dec_info,用于指示后续哪些模块需要进行运算。译码模块的代码写的很清楚,并且有比较详细的注释了,因此更多这部分的细节可以参考 E203 的 decode 模块代码,本文就不再赘述了。
2. 派遣模块
派遣模块在这里的作用是:(1)获取通用寄存器数据;(2)决定是否将数据派遣到 ALU 当中;(3)派遣的数据来自于整数寄存器还是浮点数寄存器。
派遣模块与其他模块的连接方式如下图:
左图只选取了有代表性的信号展示出来,即只展示了源操作数和写寄存器的地址是如何在这些模块中传递的。右图是 dispatch 模块的全部输入输出信号。根据上一篇文章《E203添加浮点数方法:寄存器设计》,disp_i_rs1和disp_i_rs1fp来源于两个不同的通用寄存器。dispatch 模块一旦接收到是长指令,就立刻给长指令安排一个 OITF 表项,并且询问 OITF 是否发生数据冲突,没有数据冲突时才允许往 ALU 传递 dec_info、源操作数和写寄存器地址。E203 规定,所有长指令都要经过 ALU,否则不会安排 OITF 表项。OITF 的作用就是记录长指令的读寄存器地址和写寄存器地址,并判断是否存在数据冲突。
3. E203 的浮点指令派遣模块设计
由于原 E203 的派遣模块的代码中已经考虑了存在浮点数时应该怎么判断输出数据的选择(选择整数还是浮点数),因此笔者从 dispatch 模块开始讲起。在文件 "e203_exu_disp.v" 的代码中,出现了disp_i_fpu,disp_i_fpu_rs1en,disp_i_fpu_rs1idx,disp_i_fpu_rs1fpu等相关信号,因此可以大胆地猜测,实现浮点指令的派遣,需要给 dispatch 模块增加这些端口。这里说下 disp_i_fpu_rs1en 和 disp_i_fpu_rs1fpu 的区别:根据 RISC-V 指令手册,有的浮点指令需要使用整数寄存器,因此实现浮点指令必须根据具体的指令来选择源操作数来源于整数寄存器还是浮点数寄存器。disp_i_fpu_rs1en 表明浮点指令是否需要来自于 rs1 的源操作数,disp_i_fpu_rs1fpu 则表明浮点指令所需要的来自于 rs1 的源操作数是来自于整数寄存器还是浮点寄存器。知道了这些后,就能知道 decode 模块需要增加哪些端口了。
4. E203 的浮点指令译码模块设计
浮点指令的译码在原 E203 的 decode 模块上进行改动。在 "e203_defines.v" 文件中,定义了有关浮点指令的 fpu_info_bus 的位标记,用于标记当前正在执行的指令是哪一条指令。在译码这部分,就需要根据指令输出disp_i_fpu,disp_i_fpu_rs1en,disp_i_fpu_rs1idx,disp_i_fpu_rs1fpu 这四类信息。这四类信息只能参照 RISC-V 指令手册来写,格式上可以参照原 E203 的 decode 模块的代码。这些代码并不复杂,但很繁琐,因此写的时候需要有一定的耐心。
由于 minidec 例化了 decode 模块,ifetcch 模块对 minidec 的输出做了一些处理,在这里也讲一下。原 E203 的 ifetcch 模块的代码亦存在了对浮点指令信息的使用,因此我们可以照葫芦画瓢地写出浮点专用的触发器 IR。但是笔者在这里有个疑惑:代码中给整数通用寄存器专门设置了一套整数专用的触发器 IR,并且说明若为浮点指令,则关闭该触发器,到了 disp 模块又要选择一次数据,那为什么不在 ifetch 中让整数指令和浮点指令使用同一套 IR,到 dispatch 部分才进行数据的选择呢?
ifetch 这一部分新增的浮点数相关电路如上面第三张图中红色部分所示。
5. 总结
综上所述,我们可以回答上一篇文章的 3.1 节所提出的 3 个问题:
(1)IFU 对浮点指令进行译码后,就知道了该指令是否需要读寄存器或者写寄存器,寄存器是整数通用寄存器还是浮点数通用寄存器;
(2)WB Arb 接收到 decode 单元给出的写寄存器相关信息后,就能判断出是否需要写寄存器,需要的话是写整数通用寄存器还是浮点数通用寄存器;
(3)dispatch 模块通过disp_i_fpu,disp_i_fpu_rs1en,disp_i_fpu_rs1idx,disp_i_fpu_rs1fpu 这四类信息判断出选择整数还是浮点数派遣。
以上就是本帖的内容。下一篇文章《E203添加浮点数方法:FPU控制逻辑》将讲述如何在 ALU 中设计 FPU 的控制器,以及如何和 FPU 进行通信。