简单CPU参考设计调试之DeBug—MyCPU部分
记一笔:
Run All 选项是在进入仿真页面之后才有的选项,且其运行的过程在右下角提示。
1.信号传递Bug
分别添加五段的PC信号值不难发现,IF_PC => ID_PC未通 EXE_PC,即执行阶段未接收到来自译码阶段的PC值。检查发现:
if把数据传给了id,但是id_stage里面没有进行fs_to_ds_bus_r <= fs_to_ds_bus。去id模块,发现ds_valid没有被赋值。
修改前:
修改后:
always @(posedge clk) begin // Bug 1
if(reset) begin
ds_valid <= 1'b0;
end
else if(ds_allowin) begin
ds_valid <= fs_to_ds_valid;
end
if (fs_to_ds_valid && ds_allowin) begin
fs_to_ds_bus_r <= fs_to_ds_bus;
end
end
2.典型"Z"信号Bug
这种情况往往是因为变量没有赋值造成的。找到id_stage模块发现:
load_op没有相关赋值语句。在合适的位置添加即可:
load_op表示的是load的operate部分此部分应该与lw指令相连接。
仿真Bug小插曲
完成上面的逻辑Bug,重新进行仿真,出现如下小插曲:
此种提示大部分是由于敲代码时有些变量敲错的问题,所以不用惊慌。点击ok就能查看到问题精确定位的文件路径:
以记事本打开便可以看到精确的错误定位。
我的Bug定位为:ID.stage 的第 128行和第三行
运用新工具-基于Trace比对的调试
3.Addiu指令实例传参Bug
Run All之后出现第一个trace比对错误,其比对错误信息提示来自如下相关代码:
可以看出其比对的相关信息依次是:PC值、写回的目的寄存器、写回的目的数据
分析:PC值为 0x bfc00000,其代表的具体是哪一条指令呢?
在 lab3\CPU_CDE\soft\func_lab3\obj\test.s 中搜索 bfc00000 可以看到其对应的指令:
为 0x2408 ffff 其对应的指令 001001 00000 01000 1111111111111111
查表可知,其对应的指令格式为addiu指令,且出错位置在写的数据上,所以需要排查alu模块与EXE_stage模块,发现:
EXE_stage模块参数实例化错误
更改为:
alu u_alu(
.alu_op (es_alu_op ),
.alu_src1 (es_alu_src1 ),
.alu_src2 (es_alu_src2 ),
.alu_result (es_alu_result)
);
4.Bug
可以看到 PC 出错了,肯定是要找分支指令或者跳转指令,我们看看附近的几条指令(test.s文件)。
/media/sf_func_lab3/start.S:19
bfc00004: 2408ffff li t0,-1
/media/sf_func_lab3/start.S:20
bfc00008: 100000e0 b bfc0038c <locate>
/media/sf_func_lab3/start.S:21
bfc0000c: 00000000 nop
/media/sf_func_lab3/start.S:24
bfc00010: 3c088000 lui t0,0x8000
/media/sf_func_lab3/start.S:25
bfc00014: 25290001 addiu t1,t1,1
很明显可以看到 bfc00008 这条指令是分支指令,而 mycpu 没进行跳转。
首先先说明 nop 指令,这里很善良的将延迟槽指令设置为 nop,和上面一样,nop 指令也不需要特别实现。
控制流首先流入预取指阶段,然后预取指阶段更新 PC 并且访问 RAM 获得指令,PC 和 RAM 最终同时流入译码阶段,在译码阶段通过组合逻辑控制预取指阶段完成跳转。
我们 预期的执行顺序
可以看到,在我们的预期中,分支指令的前置判断是由译码阶段完成的。
这条 B 指令由 r0 恒为 0 和 BEQ 指令得到。
我们可以发现在这条延迟槽指令时,本应有assign br_bus = {br_taken,br_target};,但是最下端两个信号却相同,所以即可找出问题。
问题出现文件路径:\lab3\CPU_CDE\mycpu_verify\rtl\myCPU\mycpu.h
更改位宽:
`define BR_BUS_WD 33
5.Bug
全局出错
这个错误还是在alu模块(前后位宽不匹配赋值):
更改:
assign sr_result = sr64_result[31:0];
6.Bug
循环这种情况是由于 RTL 代码中存在组合回路,不好找,若恰巧看到这行,它的错误还是很明显的。
alu.v模块的错误:
更改:
assign or_result = alu_src1 | alu_src2;
PC-Bug小插曲
上面依次解决完之后,重新运行发现这个现象。。。
观察发现:每次运行报错的写回级的PC与trace.txt不一致,但是其目的寄存器号和数据却是正确的。什么原因造成的呢?
7.最后一个Bug
错误文件路径:mycpu_verify => rtl => myCPU => tools.v
仔细一点就会发现这里的decoder_6_64模块的译码根本不够64位,即只有【62:0】,所以应该更改为:
generate for (i=0; i<64; i=i+1) begin:gen_for_dec_6_64 //Bug 7
成功上板视频展示:
上板实验时建议先把所有拨码开关拨上,此时的计数速度最慢,便于观察实验现象。然后可以拨下一两个,速度适中。
视频链接:简单CPU设计参考实践任务
参考:
借鉴相关博客链接:
CPU设计实战 lab3
CPU设计实战lab3—任务1 简单CPU参考设计调试