e203_exu_wbck是RISC-V处理器中的一个模块,它负责处理结果的写回。当ALU或长管道指令执行完成时,需要将计算结果写回寄存器中。而e203_exu_wbck模块则是起到了一个数据调度和结果写回的功能。具体而言,其主要功能包括:
(1)根据长管道指令和ALU指令的执行情况,实现结果写回的调度。
(2)根据结果写回调度来实现对寄存器的写入。
(3)配置RF_WBCk_O_ena、RF_WBCk_O_wdat、RF_WBCk_O_rdidx等寄存器文件写入相关信号,完成指令的执行。
该模块的输入接口有如下几个信号:
(1)alu_wbck_i_valid: ALU结果写回有效信号,表示ALU执行结束并生成了结果。
(2)alu_wbck_i_ready: ALU结果写回就绪信号,表示ALU结果写回的方向已经准备好。
(3)alu_wbck_i_wdat: ALU操作的结果数据。
(4)alu_wbck_i_rdidx: ALU指令读取的寄存器索引。
(5)longp_wbck_i_valid: 长管道指令结果写回有效信号,表示长管道指令执行结束并生成了结果。
(6)longp_wbck_i_ready: 长管道指令结果写回就绪信号,表示长管道指令结果写回的方向已经准备好。
(7)longp_wbck_i_wdat: 长管道指令操作的结果数据。
(8)longp_wbck_i_flags: 长管道指令操作标志。
(9)longp_wbck_i_rdidx: 长管道指令读取的寄存器索引。
(10)longp_wbck_i_rdfpu: 长管道指令结果是否需要被写回到FPU中。
(11)clk: 时钟信号。
(12)rst_n: 复位信号。
该模块的输出接口有如下几个信号:
(1)rf_wbck_o_ena: 寄存器文件写入使能信号。
(2)rf_wbck_o_wdat: 寄存器文件写入数据。
(3)rf_wbck_o_rdidx: 寄存器文件写入索引。
首先,需要根据长管道指令和ALU指令的执行情况,实现结果写回的调度。因为长管道指令往往有较高的优先级,所以其写回结果的权重也应该更高。因此,e203_exu_wbck模块为长管道指令分配一个专门的结果写回通路,并在该通路上进行数据写回操作。
而对于ALU指令,则需要进行一定的数据等待和选择才能完成结果的写入。具体而言,需要等待当前长管道指令执行完成并且结果写回操作完成,然后再判断ALU指令是否可以写回。如果当前长管道指令没有写回结果,那么ALU指令就不能进行写回操作。只有当长管道指令结果写回完毕,并且没有正在等待的其他指令时,ALU指令才能进行写回操作。
在执行完指令后,需要将计算结果写回寄存器中,从而完成指令的执行。这个过程需要对寄存器文件进行写入操作。为此,e203_exu_wbck模块配置了相应的RF_WBCk_O_ena、RF_WBCk_O_wdat、RF_WBCk_O_rdidx等寄存器文件写入相关信号,来完成指令的执行。
在代码实现的过程中,需要注意一些细节问题和注意事项。其中,以下是一些我认为比较重要的点:
(1)如果ALU发生错误或没有读取寄存器,则不会将结果写回到寄存器文件中。
(2)对于FPU结果写入,需要根据E203_FLEN_IS_32宏定义来进行判断和处理。
(3)长管道指令具有更高的优先级,因此需要为其分配专用的结果写回通路。
(4)需要等待当前长管道指令执行完成并且结果写回操作完成,然后再判断ALU指令是否可以写回。
(5)为了完成指令的执行,需要将计算结果写回到寄存器文件中。
(6)需要在代码实现过程中考虑到时序问题,特别是在数据调度和写回策略的实现中,需要保证正确性和完整性。
下面是代码的相关注释
// 包含定义文件
include “e203_defines.v”
// 定义模块 e203_exu_wbck
module e203_exu_wbck(
// ALU 写回接口
input alu_wbck_i_valid, // 握手信号有效
output alu_wbck_i_ready, // 握手信号准备好
input [E203_XLEN-1:0] alu_wbck_i_wdat, input [E203_RFIDX_WIDTH-1:0] alu_wbck_i_rdidx,
// Long Pipeline 写回接口
input longp_wbck_i_valid, // 握手信号有效
output longp_wbck_i_ready, // 握手信号准备好
input [E203_FLEN-1:0] longp_wbck_i_wdat, input [5-1:0] longp_wbck_i_flags, input [E203_RFIDX_WIDTH-1:0] longp_wbck_i_rdidx,
input longp_wbck_i_rdfpu,
// 最终仲裁写回接口到 Regfile
output rf_wbck_o_ena,
output [E203_XLEN-1:0] rf_wbck_o_wdat, output [E203_RFIDX_WIDTH-1:0] rf_wbck_o_rdidx,
input clk,
input rst_n
);
// ALU 指令只有在没有任何长流水线指令写回时才能执行写回
// * 因为 ALU 是 1 周期指令,所以它具有最低的优先级
wire wbck_ready4alu = (~longp_wbck_i_valid);
wire wbck_sel_alu = alu_wbck_i_valid & wbck_ready4alu;
// 长流水线指令可以随时写回,因为它具有高优先级
wire wbck_ready4longp = 1’b1;
wire wbck_sel_longp = longp_wbck_i_valid & wbck_ready4longp;
// 最终仲裁写回接口
wire rf_wbck_o_ready = 1’b1; // Regfile 总是准备好进行写入,因为它只有 1 个写入端口
// 写回信号输入端口
wire wbck_i_ready;
wire wbck_i_valid;
wire [E203_FLEN-1:0] wbck_i_wdat; wire [5-1:0] wbck_i_flags; wire [E203_RFIDX_WIDTH-1:0] wbck_i_rdidx;
wire wbck_i_rdfpu;
// 根据选择的信号类型,选择对应的写回接口
assign alu_wbck_i_ready = wbck_ready4alu & wbck_i_ready;
assign longp_wbck_i_ready = wbck_ready4longp & wbck_i_ready;
assign wbck_i_valid = wbck_sel_alu ? alu_wbck_i_valid : longp_wbck_i_valid;
// 如果 E203_FLEN_IS_32 宏被定义,则将 ALU 的写回数据直接赋值给 wbck_i_wdat,
// 否则需要将 ALU 的写回数据高位填充为 0,并与 longp 写回数据拼接
ifdef E203_FLEN_IS_32//{ assign wbck_i_wdat = wbck_sel_alu ? alu_wbck_i_wdat : longp_wbck_i_wdat; else//}{
assign wbck_i_wdat = wbck_sel_alu ? {{E203_FLEN-E203_XLEN{1’b0}},alu_wbck_i_wdat} : longp_wbck_i_wdat;
`endif//}
assign wbck_i_flags = wbck_sel_alu ? 5’b0 : longp_wbck_i_flags;
assign wbck_i_rdidx = wbck_sel_alu ? alu_wbck_i_rdidx : longp_wbck_i_rdidx;
assign wbck_i_rdfpu = wbck_sel_alu ? 1’b0 : longp_wbck_i_rdfpu;
// 如果存在错误或非 rdwen,则不会发送到此模块,而是在 EU 级别被终止
// 因此它始终需要在此处写回到 regfile
assign wbck_i_ready = rf_wbck_o_ready;
wire rf_wbck_o_valid = wbck_i_valid;
wire wbck_o_ena = rf_wbck_o_valid & rf_wbck_o_ready;
assign rf_wbck_o_ena = wbck_o_ena & (~wbck_i_rdfpu);
assign rf_wbck_o_wdat = wbck_i_wdat[`E203_XLEN-1:0];
assign rf_wbck_o_rdidx = wbck_i_rdidx;
endmodule