CPU设计实战 第四章实践任务一 第一个bug

文章详细描述了一个在CPU设计中遇到的信号异常问题,即一个变量值为不定值X。作者通过逐步排查,从RTL层的变量声明到各级Stage的信号传递,发现并修复了阻塞赋值和缺失valid位赋值的问题,最终解决了bug。
摘要由CSDN通过智能技术生成

第一个bug

debug_wb_pc = 0xxxxxxxxx

可看到信号为X,X是不定值,而这种错误往往是下面两种原因之一导致的:

  1. RTL里声明为reg型的变量从未被赋值

  2. RTL里存在多驱动的代码

首先,从第一种情况开始排查,由变量名debug_wb_pc可知该变量应该位于写回阶段里,打开WB_stage.v,查找变量debug_wb_pc,

发现:

 assign debug_wb_pc    = ws_pc;

可知debug_wb_pc的值由ws_pc得到,所以下一步就是查找wc_pc的值是从哪里得到的,发现:

 assign {ws_gr_we       ,  //69:69
         ws_dest        ,  //68:64
         ws_final_result,  //63:32
         ws_pc             //31:0
        } = ms_to_ws_bus_r;

ws_pc的值与ms_to_ws_bus_r有关,继续查找ms_to_ws_bus_r的值是从哪里得到的,发现:

 always @(posedge clk) begin
     if (reset) begin
         ws_valid <= 1'b0;
     end
     else if (ws_allowin) begin
         ws_valid <= ms_to_ws_valid;
     end
 ​
     if (ms_to_ws_valid && ws_allowin) begin
         ms_to_ws_bus_r = ms_to_ws_bus;
     end
 end

发现ms_to_ws_bus_r的值与ms_to_ws_bus有关,实际上这里有一个小bug,在always语句里应该使用非阻塞赋值,而这里使用的是阻塞赋值,将ms_to_ws_bus_r = ms_to_ws_bus;修改为ms_to_ws_bus_r <= ms_to_ws_bus;我原本以为这就是第一个bug,结果我运行仿真的时候发现还是报debug_wb_pc = 0xxxxxxxxx这个错,那说明真的的bug我还没找到,所以就继续以ms_to_ws_bus往下找,由名字ms_to_ws_bus可看出它与访存阶段和写回阶段有关,写回阶段没发现什么问题,所以去访存阶段里找,打开MEM_stage.v,发现:

 assign ms_to_ws_bus = {ms_gr_we       ,  //69:69
                        ms_dest        ,  //68:64
                        ms_final_result,  //63:32
                        ms_pc             //31:0
                       };

ms_to_ws_bus与ms_gr_we,ms_dest,ms_final_result,ms_pc 有关,接着继续找ms_gr_we,ms_dest,ms_final_result,ms_pc这些变量和谁有关,发现:

 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;到这里就可以发现接下来的步骤就和上面排查ms_to_ws_bus的步骤一样了。打开EXE.stage.v,可发现es_to_ms_bus与ds_to_es_bus_r有关,而ds_to_es_bus_r的值又与ds_to_es_bus相关,所以下一步就是打开ID_stage.v继续排查,步骤还是和上面一样,首先发现ds_to_es_bus与fs_to_ds_bus_r有关,到这里终于发现了问题:

 always @(posedge clk) begin
     if (fs_to_ds_valid && ds_allowin) begin
         fs_to_ds_bus_r <= fs_to_ds_bus;
     end
 end

发现在这个always中没有对ds_valid进行赋值,ds_valid是译码级的有效位,当他的值为1时表示该流水线上当前时钟周期存在有效的数据,值为0时表示该流水线上当前时钟周期为空。具体可看CPU设计实战P55页。

将代码修改为:

 always @(posedge clk) begin
    //第一个bug
     if(reset) begin
         ds_valid = 1'b0;
     end
     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

解决第一个bug。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值