[ 2067 ns] Error!!! reference: PC = 0xbfc00000, wb_rf_wnum = 0x08, wb_rf_wdata = 0xffffffff mycpu : PC = 0xbfc00000, wb_rf_wnum = 0x08, wb_rf_wdata = 0xxxxxxxxX
由报错信息可知wb_rf_wdata的值应该为0xffffffff,而现在却是0xxxxxxxxX,而出现X的常见原因在第一个bug里已说明,下面要做的就是找到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_res_from_mem的值为Z,这便是导致出错的其中一个原因,但是这并不是最根本的原因,根本原因是找到ms_res_from_mem的值为什么是Z。而信号为Z这种错误往往是由下面两个原因导致的:
-
RTL里声明为wire型的变量从未被赋值。
-
模块调用的信号未连接导致信号悬空。
接下来就是排查ms_res_from_mem出现Z的原因,发现:
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;
所以接下来查找es_to_ms_bus_r和什么有关,发现es_to_ms_bus_r的值是由es_to_ms_bus赋值得到的,所以接下来排查es_to_ms_bus,打开MEM_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_res_from_mem的值由es_res_from_mem得到,紧接着发现:
assign es_res_from_mem = es_load_op;
查找es_load_op发现:
assign {es_alu_op , //135:124
es_load_op , //123:123
es_src1_is_sa , //122:122
es_src1_is_pc , //121:121
es_src2_is_imm , //120:120
es_src2_is_8 , //119:119
es_gr_we , //118:118
es_mem_we , //117:117
es_dest , //116:112
es_imm , //111:96
es_rs_value , //95 :64
es_rt_value , //63 :32
es_pc //31 :0
} = ds_to_es_bus_r;
发现es_load_op与ds_to_es_bus_r有关,而ds_to_es_bus_r的值又与ds_to_es_bus有关,接下来排查ds_to_es_bus,打开ID_stage.v,查找ds_to_es_bus,发现:
assign ds_to_es_bus = {alu_op , //135:124
load_op , //123:123
src1_is_sa , //122:122
src1_is_pc , //121:121
src2_is_imm , //120:120
src2_is_8 , //119:119
gr_we , //118:118
mem_we , //117:117
dest , //116:112
imm , //111:96
rs_value , //95 :64
rt_value , //63 :32
ds_pc //31 :0
};
与上面的ds_to_es_bus_r对照发现es_load_op的值由load_op得到,接下来查找load_op,发现load_op只进行了定义:
wire load_op;
却未对load_op赋值,这就是导致前面信号出现Z的原因,接下来我们要给load_op赋值,而给load_op赋什么值呢?我们需要看load_op用于什么指令,因为load_op用在ds_to_es_bus,所以我们向执行阶段找,回到MEM_stage.v,查找ds_to_es_bus发现ds_to_es_bus_r用到了ds_to_es_bus的值,继续查看ds_to_es_bus_r发现:
assign {es_alu_op , //135:124
es_load_op , //123:123
es_src1_is_sa , //122:122
es_src1_is_pc , //121:121
es_src2_is_imm , //120:120
es_src2_is_8 , //119:119
es_gr_we , //118:118
es_mem_we , //117:117
es_dest , //116:112
es_imm , //111:96
es_rs_value , //95 :64
es_rt_value , //63 :32
es_pc //31 :0
} = ds_to_es_bus_r;
其中包括es_load_op,在前面的分析中我们知道es_load_op和load_op的值一样,所以接下来我们排查es_load_op发现:
assign es_res_from_mem = es_load_op;
发现与es_res_from_mem有关,从这可以看出load_op指令是一条与访存有关的指令。(实际上该结论在我们前面排查的时候应该就已经得到了)而lab3一共实现了19条指令,这19条指令里只有两条和访存有关,①LW(取字),②SW(存字)。这里很明显访存是取字,所以我们知道了load_op在这里应该执行的是LW指令,所以回到ID_stage.v添加代码给load_op赋值:
assign load_op = inst_lw;
至此第二个bug解决。