状态机怎么上来就错了?怎么解决?

电子说

1.2w人已加入

描述

事故现场

先贴一下代码的简版:

localparam S_IDLE    = 4'd0;
localparam S_HEAD    = 4'd1;
localparam S_PAYLOAD = 4'd2;
localparam S_TAIL    = 4'd3;
localparam S_ERROR   = 4'd4;

reg [3:0]status, nx_status;
always @(posedge clk_100m or negedge rst_spt_n)begin
    if(!rst_spt_n) status <= S_IDLE;
    else           status <= nx_status;
end

always @* begin
    case(status)
        S_IDLE: ...
        S_HEAD: ...
        S_PAYLOAD: ...
        S_TAIL: ...
        S_ERROR: ...
        default: nx_status = status;
    endcase
end

状态机本身很简单,default也写了,然后进行仿真时看到了这样的波形:

状态机

nx_status仿真初始的值为4'hb,而后导致status的值也为4'hb,始终无法回到IDLE状态,整个电路的功能也无法正常开展。

事故分析

这个问题得以暴露要感谢在验证环境中打开了initreg功能:

CMP_OPTIONS += +vcs+initreg+random
RUN_OPTIONS += +vcs+initreg+$(SEED)

通过这样的配置使得reg型的数值在仿真开始时被赋值为随机数。该bug就是由于nx_status被赋值为状态之外的随机数而发现的。

在代码中,nx_status没有任何位置被进行“复位”,当然了因为nx_status本身不是寄存器也就不存在复位的问题,不过状态机的alway@*中的处理是有问题的,这导致nx_status一旦跑“飞”了,status下一拍会更新为nx_status的值,那么整个状态机将不可恢复。

事故解决

修改状态机的写法为:

always @* begin
    case(status)
        S_IDLE: ...
        S_HEAD: ...
        S_PAYLOAD: ...
        S_TAIL: ...
        S_ERROR: ...
        default: nx_status = S_IDLE;
    endcase
end

或者

always @* begin
    nx_status = S_IDLE;
    case(status)
        S_IDLE: ...
        S_HEAD: ...
        S_PAYLOAD: ...
        S_TAIL: ...
        S_ERROR: ...
        default: nx_status = status;
    endcase
end

重新仿真后波形正确:

状态机

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分