状态机fsm_有限状态机 FSM 的仿真的小 Tip

faf079ac6ac3e468280840e990a967d4.png

作为一名极其低产的一名“作者”,2021年也要写上一篇文章吧。作为今年的第一篇博文,想和大家聊聊 FSM 仿真时可能遇到的一些问题。

具体的 FSM 如何书写,这里送上“十二点过九分”的一篇文章的链接。

十二点过九分:【划水】怎么写一个有限状态机?​zhuanlan.zhihu.com
e4f73dfa22fad07e786d9ea69f22a469.png

下面言归正传,在编写 FSM 测试程序时,经常需要检查 FSM 的“状态”,常规的做法是:

  1. 在利用 Modelsim 仿真时,我们将次级目录下的定义的 state 单独拉出来,查看状态跳转情况。这样的作法虽然可以看到,但是仿真的波形上都是所定义子状态的 0/1 二进制编码。不会直观的显示当前的状态名(如何你的记忆力足够强大,则可以直接忽略笔者的这篇文章)
  2. 采用打印的方式,例如利用 $display 函数,在命令行中显示,但是波形中又无法体现。

因此,有这么一种“奇淫技巧”(至少笔者是这么认为的),那便是在 testbench直接引用该状态变量,并通过 case 语句将 state 转换为自然语言表述。

下面给出具体的操作步骤,操作步骤参考[1]。

第一步:在 testbench 中定义 reg 型变量,用于存储ASCII字符串。例如,下面定义了最大长度为5字符串。

reg [5*8-1:0] current_state_name ;

第二步:利用模块变量的直接引用,并通过case将状态机的各个状态与自然语言一一对应起来

always@(tb_ASCII_state.UUU.current_state or tb_ASCII_state.UUU.next_state)begin
    case(tb_ASCII_state.UUU.current_state)
        IDLE    :test_current_state = "IDLE"        ;
        PROCESS :test_current_state = "PROCESS"     ;
        END_S   :test_current_state = "END_S"       ;
        default :test_current_state = "ERROR"       ;   
    endcase

    case(tb_ASCII_state.UUU.next_state)
        IDLE    :test_next_state = "IDLE"        ;
        PROCESS :test_next_state = "PROCESS"     ;
        END_S   :test_next_state = "END_S"       ;
        default :test_next_state = "ERROR"       ;   
    endcase
end

第三步:在Modelsim的波形窗口界面中,将前面定义的reg型变量转换为ASCII显示。

下面给出本次所用的完整的测试用例

工程文件

module ASCII_state(
    input           sys_clk     ,
    input           rst_n       ,
    output  reg     state_out   
);


reg     [2:0]   current_state,next_state   ;

localparam      IDLE    =   3'b001  ,
                PROCESS =   3'b010  ,
                END_S   =   3'b100  ;

always@(posedge sys_clk or negedge rst_n)begin
    if(!rst_n)begin
        current_state       <=      IDLE        ;
    end
    else begin
        current_state       <=      next_state  ;
    end
end

always@(*)egin
    case(current_state)
        IDLE:begin
            state_out       =       1'b1    ;
            next_state      =       PROCESS ;
        end
        PROCESS:begin
            state_out       =       1'b1    ;
            next_state      =       END_S   ;
        end
        END_S:begin
            state_out       =       1'b0    ;
            next_state      =       IDLE    ;
        end
        default:begin
            state_out       =       1'b0    ;
            next_state      =       IDLE    ;
        end
    endcase
end

endmodule

仿真文件

module tb_ASCII_state;

reg         sys_clk         ;
reg         rst_n           ;
wire        state_out       ;

initial sys_clk =   1   ;

always#5 sys_clk    =   ~sys_clk;

initial begin
    rst_n = 0   ;
    #50;
    rst_n = 1   ;
end

ASCII_state     UUU(
    .sys_clk     (sys_clk  ),
    .rst_n       (rst_n    ),
    .state_out   (state_out)
);


reg     [8*8-1:0]   test_current_state,test_next_state;


localparam      IDLE    =   3'b001  ,
                PROCESS =   3'b010  ,
                END_S   =   3'b100  ;


always@(tb_ASCII_state.UUU.current_state or tb_ASCII_state.UUU.next_state)begin
    case(tb_ASCII_state.UUU.current_state)
        IDLE    :test_current_state = "IDLE"        ;
        PROCESS :test_current_state = "PROCESS"     ;
        END_S   :test_current_state = "END_S"       ;
        default :test_current_state = "ERROR"       ;   
    endcase

    case(tb_ASCII_state.UUU.next_state)
        IDLE    :test_next_state = "IDLE"        ;
        PROCESS :test_next_state = "PROCESS"     ;
        END_S   :test_next_state = "END_S"       ;
        default :test_next_state = "ERROR"       ;   
    endcase
end

波形仿真

从仿真波形上来看,功能基本正确。

5912341960950b4328b0da70193de30f.png

基于以上操作,面对状态跳转的问题,就不存在对一连串的0101...而发愁了 。

参考

[1] 李庆华著《通信IC设计》.机械工业出版社

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值