[ 888537 ns] Error!!! reference: PC = 0xbfc88c90, wb_rf_wnum = 0x02, wb_rf_wdata = 0xadff20c0 mycpu : PC = 0xbfc88c90, wb_rf_wnum = 0x02, wb_rf_wdata = 0x2dff20c0
从报错信息上来看,PC值是对的,但是wb_rf_wdata的值是错的,从报错可以看出是wb_rf_wdata的值应该是0xadff20c0而此时是0x2dff20c0,下面要做的就是找到bug位于哪里,由变量名wb_rf_wdata可知,该变量应该在访存阶段,打开WB.stage.v,找到wb_rf_wdata变量发现:
assign debug_wb_rf_wdata = ws_final_result;
继续查找wc_final_result与什么有关:
assign {ws_gr_we , //69:69
ws_dest , //68:64
ws_final_result, //63:32
ws_pc //31:0
} = ms_to_ws_bus_r;
发现wc_final_result是由ms_to_ws_bus_r赋值的,由ms_to_ws_bus_r继续找下去,发现:
ms_to_ws_bus_r <= ms_to_ws_bus;
所以接下来找ms_to_ws_bus和什么相关,打开MEM_stage.v查找ms_to_ws_bus发现:
assign ms_to_ws_bus = {ms_gr_we , //69:69
ms_dest , //68:64
ms_final_result, //63:32
ms_pc //31:0
};
由此可知,ws_final_result的值是由ms_final_result传递过去的,接下来查找ms_final_result发现:
assign ms_final_result = ms_res_from_mem ? mem_result
: ms_alu_result;
ms_final_result的值由该问号表达式决定,通过查看波形发现ms_res_from_mem的值为0,所以ms_final_result=ms_alu_result,ms_alu_result的值出错就是导致错误的原因,下面继续追ms_alu_result发现:
assign {ms_res_from_mem, //70:70
ms_gr_we , //69:69
ms_dest , //68:64
ms_alu_result , //63:32
ms_pc //31:0
} = es_to_ms_bus_r;
ms_alu_result与es_to_ms_bus_r有关,而es_to_ms_bus_r又与es_to_ms_bus有关,接下来打开EXE_stage.v,查找es_to_ms_bus发现:
assign es_to_ms_bus = {es_res_from_mem, //70:70
es_gr_we , //69:69
es_dest , //68:64
es_alu_result , //63:32
es_pc //31:0
};
所以 ms_alu_result的值由es_alu_result得到,接下来排查es_alu_result发现:
alu u_alu(
.alu_op (es_alu_op ),
.alu_src1 (es_alu_src1 ),
.alu_src2 (es_alu_src2 ),
.alu_result (es_alu_result)
);
通过波形查看es_alu_result的值发现,此时es_alu_result的值为0x2dff20c0,因为.alu_result是output变量,所以判断是ALU内部出现了错误,我们先查看一下PC=0xbfc88c90执行的是什么操作,打开test.s查看反汇编代码,搜索xbfc88c90,发现:
bfc88c90: 00081002 srl v0,t0,0x0
所以执行的是SRL逻辑右移操作,接下来打开alu.v排查SRL相关代码,首先看到控制信号op_srl,通过波形查看到op_srl此时的值确实是1,接着继续查找发现:
assign alu_result = ({32{op_add|op_sub}} & add_sub_result)
| ({32{op_slt }} & slt_result)
| ({32{op_sltu }} & sltu_result)
| ({32{op_and }} & and_result)
| ({32{op_nor }} & nor_result)
| ({32{op_or }} & or_result)
| ({32{op_xor }} & xor_result)
| ({32{op_lui }} & lui_result)
| ({32{op_sll }} & sll_result)
| ({32{op_srl|op_sra}} & sr_result); // op_srl表示逻辑右移,op_sra表示算术右移
可看到当op_srl的值为1的时候,alu_result=sr_result,接下来查看sr_result的值和什么有关,发现:
// SRL, SRA result
assign sr64_result = {{32{op_sra & alu_src2[31]}}, alu_src2[31:0]} >> alu_src1[4:0];
assign sr_result = sr64_result[30:0];
看到这里,通过波形查看sr64_result的值,发现是0xadff20c0(10101101111111110010000011000000),而sr_result的值是0x2dff20c0(00101101111111110010000011000000)只有一位的差别,这下就明白了,错误的原因就是sr64_result[30:0]这里位宽写错了,应该是32位,而这里只有31位,修改代码如下:
// SRL, SRA result
assign sr64_result = {{32{op_sra & alu_src2[31]}}, alu_src2[31:0]} >> alu_src1[4:0];
assign sr_result = sr64_result[31:0];
值得一提的是这里通过利用op_sra & alu_src2[31]巧妙的将逻辑右移和算术右移的结果都用sr_result来表示,当op_sra为0时表示执行的是SRL(逻辑右移),右移后左边补32个0,sr64_result[31:0]就是逻辑右移的结果。当op_sra为1时,表示执行的是SRA(算术右移),右移后左边补32个符号位(正数补0,负数补1),此时sr64_result[31:0]就是算术右移的结果。
至此第六个bug解决,第四章实践任务一的所有bug全部解决。
此时测试已通过。