zoukankan      html  css  js  c++  java
  • 时序逻辑中阻塞赋值引起的仿真问题

    最近写了一个分频的代码,但是在仿真中遇到了一个小问题,具体代码如下:

    分频代码(该模块功能为将50MHz时钟分频为10Hz)

    module div_fre(
    //-------------------------------Port Declaration---------------------------------
                    
            output          o_clk_100Hz,
            input           i_sys_clk_50MHz,
            input           i_sys_reset
            
        );
    //-------------------------------Define Parameter---------------------------------
            parameter       div_cnt_max     =       23'd4999999;
            parameter       div_cnt_half    =       23'd2499999;
    //-------------------------------Internal Registers-------------------------------
            reg     [22:0]  div_cnt         =       23'd0;
            reg             fall_en         =       1'b0;
            reg             rise_en         =       1'b0;
            reg             clk_temp        =       1'b0;
    //-------------------------------Internal Wire------------------------------------
    
    //-------------------------------Code Starts Here---------------------------------
                    
    always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            if(i_sys_reset)
                    div_cnt <= 23'd0;
            else if(div_cnt == div_cnt_max)
                    div_cnt <= 23'd0;
            else
                    div_cnt <= div_cnt + 1;
    end
    
    /*
    always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            if(i_sys_reset)
                    fall_en <= 1'b0;
            else begin
                    if(div_cnt == div_cnt_half - 1)
                            fall_en <= 1'b1;
                    else
                            fall_en <= 1'b0;
            end
    end
    always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            if(i_sys_reset)
                    rise_en <= 1'b0;
            else begin
                    if(div_cnt == div_cnt_max - 1)
                            rise_en <= 1'b1;
                    else
                            rise_en <= 1'b0;
            end
    end
    always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            if(i_sys_reset)
                    clk_temp <= 1'b1;
            else begin
                    if(fall_en)
                            clk_temp <= 1'b0;
                    else if(rise_en)
                            clk_temp <= 1'b1;
                    else
                            clk_temp <= clk_temp;
            end
    end
    */  
    
    always@ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            fall_en = (i_sys_reset) ? (1'b0) : 
                                    ((div_cnt == div_cnt_half - 1) ? (1'b1) : (1'b0));
    end
    always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            rise_en = (i_sys_reset) ? (1'b0) : 
                                    ((div_cnt == div_cnt_max - 1) ? (1'b1) : (1'b0));
    end
    
    always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            clk_temp = (i_sys_reset) ? (1'b1) : 
                                     ((fall_en) ? (1'b0) : ((rise_en) ? (1'b1) : (clk_temp)));
    end 
    assign o_clk_100Hz = clk_temp;
    endmodule
    

    激励文件为:

    module div_fre_tb;
    
            // Inputs
            reg i_sys_clk_50MHz;
            reg i_sys_reset;
    
            // Outputs
            wire o_clk_100Hz;
            
            parameter       HALF_PERIOD = 10;
    
            // Instantiate the Unit Under Test (UUT)
            div_fre uut (
                    .o_clk_100Hz(o_clk_100Hz), 
                    .i_sys_clk_50MHz(i_sys_clk_50MHz), 
                    .i_sys_reset(i_sys_reset)
            );
    
            initial begin
                    // Initialize Inputs
                    i_sys_clk_50MHz = 1;
                    i_sys_reset = 1;
    
                    // Wait 100 ns for global reset to finish
                    #100;
            i_sys_reset = 0;
                    // Add stimulus here
    
            end
    
            initial begin
                    #HALF_PERIOD
                            forever
                                    #HALF_PERIOD i_sys_clk_50MHz = ~i_sys_clk_50MHz;
            end
      
    endmodule
                            
    

    功能仿真波形为:

    从仿真波形可以看出来clk_temp跳变的时刻跟我所设计的跳变时刻不太符合,本来应该是i_sys_clk_50MHz的上升沿去采fall_en的高电平来产生clk_temp = 0,可是从仿真波形中可以看到clk_temp信号是在fall_en变高的一开始就进行了变化。我通过chipscope在线调试,将程序下载到FPGA中进行在线调试却是正常的,可以看到clk_temp在fall_en=1的结束位置进行了跳变。为什么功能仿真会出现这样的问题呢?

    我重新看了代码,并重新用传统的always块的方法重新写了程序(具体为程序中注释的部分),如下:

    always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            if(i_sys_reset)
                    fall_en <= 1'b0;
            else begin
                    if(div_cnt == div_cnt_half - 1)
                            fall_en <= 1'b1;
                    else
                            fall_en <= 1'b0;
            end
    end
    always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            if(i_sys_reset)
                    rise_en <= 1'b0;
            else begin
                    if(div_cnt == div_cnt_max - 1)
                            rise_en <= 1'b1;
                    else
                            rise_en <= 1'b0;
            end
    end
    always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            if(i_sys_reset)
                    clk_temp <= 1'b1;
            else begin
                    if(fall_en)
                            clk_temp <= 1'b0;
                    else if(rise_en)
                            clk_temp <= 1'b1;
                    else
                            clk_temp <= clk_temp;
            end
    end
    

    通过仿真,波形如下:

    可以看到仿真波形跟想要的是一样的。

    通过代码对比,发现问题出在了

    always@ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            fall_en = (i_sys_reset) ? (1'b0) : 
                                    ((div_cnt == div_cnt_half - 1) ? (1'b1) : (1'b0));
    end
    always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            rise_en = (i_sys_reset) ? (1'b0) : 
                                    ((div_cnt == div_cnt_max - 1) ? (1'b1) : (1'b0));
    end
    
    always @ (posedge i_sys_clk_50MHz or posedge i_sys_reset) begin
            clk_temp = (i_sys_reset) ? (1'b1) : 
                                     ((fall_en) ? (1'b0) : ((rise_en) ? (1'b1) : (clk_temp)));
    end 
    

    这段代码中的阻塞赋值。我开始认为这段代码中每个always块中只有一句话,可以不用考虑阻塞和非阻塞赋值。但是出了问题锁定到这个地方的时候,详细想一想,由于是采用阻塞赋值,在时钟上升沿,两个always块是并行执行的。在verilog中两个always块的执行可以按照任何顺序执行。而这种先后顺序导致的仿真结果也是不一样的。所以以后写代码需要在此加以注意。

    By:冰风溪谷

  • 相关阅读:
    【洛谷 p3386】模板-二分图匹配(图论)
    【洛谷 p3374】模板-树状数组 1(数据结构)
    【poj 3167】Cow Patterns(字符串--KMP匹配+数据结构--树状数组)
    【洛谷 p3368】模板-树状数组 2(数据结构)
    【洛谷 P3385】模板-负环(图论--spfa)
    【poj 3080】Blue Jeans(字符串--KMP+暴力枚举+剪枝)
    【poj 2185】Milking Grid(字符串--KMP+问题分解)
    【poj 3461】Oulipo(字符串--KMP)
    正则表达式
    表单
  • 原文地址:https://www.cnblogs.com/icelyb24/p/2221617.html
Copyright © 2011-2022 走看看