流水线的数据冲突
译码阶段的数据冲突
ID模块通过译码和读取regfile寄存器,确定后续阶段所需要的源操作数等,在流水线的条件下,就有可能造成“写后读”的数据相关问题
采用数据前推的方式将将要写入regfile的数据和寄存器信息传送到ID模块,进行判断
解决
ID模块接收由EX、MEM、WB模块传送过来的写信息
另外还接收了load_op信号,这里的load_op信号其实是上一个节拍从ID模块的得到的,相当与经过一个流水线寄存器打了一拍,这个信息可以用来处理load相关
// ID模块接收其他模块传来的信息
assign {es_valid, // 117:117
es_load_op, // 116:116
es_rf_we, // 115:115
es_rf_waddr, // 114:110
es_rf_wdata, // 109: 78
ms_valid, // 77: 77
ms_rf_we, // 76: 76
ms_rf_waddr, // 75: 71
ms_rf_wdata, // 70: 39
ws_valid, // 38: 38
ws_rf_we, // 37: 37
ws_rf_waddr, // 36: 32
ws_rf_wdata // 31: 0
} = data_hazard_bus;
处理load相关
单数据的相关在EX阶段就算出来写入结果了,而load指令的写入的结果在MEM阶段才能得到,所以需要对应的指令的ID模块多暂停一拍,等到load指令算出来结果,之后在通过数据前推端口解决相关问题。
// load hazard
wire load_hazard_occur;
assign load_hazard_occur = es_hazard_occur && es_load_op;
// 流水线暂停
wire hazard_occur_stall;
assign hazard_occur_stall = load_hazard_occur;
// assign ds_ready_go = 1'b1;
assign ds_ready_go = !hazard_occur_stall;
处理数据相关
// data hazard
// determine if this inst requires RS as src
wire inst_req_rs;
assign inst_req_rs = inst_addu | inst_addiu | inst_subu | inst_slt | inst_sltu |
inst_and | inst_or | inst_xor | inst_nor | inst_lw |
inst_sw | inst_beq | inst_bne | inst_jr ;
// determine if this inst requires RT as src
wire inst_req_rt;
assign inst_req_rt = inst_addu | inst_subu | inst_slt | inst_sltu | inst_and |
inst_or | inst_xor | inst_nor | inst_sll | inst_srl |
inst_sra | inst_beq | inst_bne | inst_sw;
// when this inst require rs|rt as their src register and rs|rt not equal to r0
// this inst is likely to occur data hazard
wire rs_hazard_likely;
wire rt_hazard_likely;
assign rs_hazard_likely = inst_req_rs && (rs != 5'h00);
assign rt_hazard_likely = inst_req_rt && (rt != 5'h00);
// 检查是否发生冲突
wire es_hazard_occur;
wire ms_hazard_occur;
wire ws_hazard_occur;
assign es_hazard_occur = es_valid && es_rf_we &&
( (rs_hazard_likely && es_rf_waddr == rs) ||
(rt_hazard_likely && es_rf_waddr == rt) );
assign ms_hazard_occur= ms_valid && ms_rf_we &&
( (rs_hazard_likely && ms_rf_waddr == rs) ||
(rt_hazard_likely && ms_rf_waddr == rt) );
assign ws_hazard_occur = ws_valid && ws_rf_we &&
( (rs_hazard_likely && ws_rf_waddr == rs) ||
(rt_hazard_likely && ws_rf_waddr == rt) );
// 确定最终源操作数
assign rs_value = (es_hazard_occur && es_rf_waddr == rs) ? es_rf_wdata :
(ms_hazard_occur && ms_rf_waddr == rs) ? ms_rf_wdata :
(ws_hazard_occur && ws_rf_waddr == rs) ? ws_rf_wdata :
rf_rdata1;
assign rt_value = (es_hazard_occur && es_rf_waddr == rt) ? es_rf_wdata :
(ms_hazard_occur && ms_rf_waddr == rt) ? ms_rf_wdata :
(ws_hazard_occur && ws_rf_waddr == rt) ? ws_rf_wdata :
rf_rdata2;