一、滞后一拍的现象

1、Verilog代码

module flip_flop(
    input     wire         sys_clk    ,
    input     wire         sys_rst_n  ,
    input     wire         key_in     ,
    output   reg          led_out 
);

// asynchronous reset D flip-flop
always @(posedge sys_clk) begin 
    if (sys_rst_n == 1'b0) 
         led_out <= 1'b0;
    else 
         led_out <= key_in;
end

2、仿真现象
在这里插入图片描述

如图所示,led_out输出总比key_in输出延迟一个时钟周期


二、产生此现象的原因

主要是非阻塞赋值与阻塞语句赋值的原因
解释如下:
①首先我们来看这一个代码段产生的效果
代码段:(主要是注意always块中的非阻塞赋值)

module blocking(
    input   wire            sys_clk         ,
    input   wire            sys_rst_n       ,
    input   wire  [1:0]     in              ,
    output  reg   [1:0]     out      
);

reg [1:0]  in_reg;

always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n) begin
        in_reg <= 2'b00;
        out    <= 2'b00;
    end
    else begin
        in_reg <= in;             // 注意这一行
        out    <= in_reg;         // 也要注意这一行,都是非阻塞赋值
    end
end

endmodule

Testbench代码段:

module tb_blocking();

reg   sys_clk;
reg   sys_rst_n;
reg   [1:0]  in;

// blocking Outputs
wire  [1:0]  out;


initial begin
    sys_clk = 1'b1;
    sys_rst_n <= 1'b0;
    in  <= 2'b00;
    #20
    sys_rst_n <= 1'b1;
end

always #10 sys_clk = ~sys_clk;
always #20 in <= {$random} % 4;


blocking  blocking_inst(
    .sys_clk                 ( sys_clk     ),
    .sys_rst_n               ( sys_rst_n   ),
    .in                      ( in          ),

    .out                     ( out         )
);

endmodule

产生的效果:
在这里插入图片描述

我们可以看到,in_reg总是滞后in一个时钟周期,out滞后in_reg一个时钟周期

②当我们把代码中always块的非阻塞赋值改为阻塞赋值时
代码段:

module blocking(
    input   wire            sys_clk         ,
    input   wire            sys_rst_n       ,
    input   wire  [1:0]     in              ,
    output  reg   [1:0]     out      
);

reg [1:0]  in_reg;

always @(posedge sys_clk or negedge sys_rst_n) begin
    if (!sys_rst_n) begin
        in_reg <= 2'b00;
        out    <= 2'b00;
    end
    else begin
        in_reg = in;        // 注意这一行
        out    = in_reg;    // 也注意这一行,阻塞赋值
    end
end

endmodule

同上的Testbench,产生的仿真效果
在这里插入图片描述

我们可以看到,in_reg滞后in一个时钟周期,out居然不滞后in_reg了,这是为什么呢?



只能意会,不能言传,因为赋值语句,在赋值时候,相当于右边的信号有一个寄存器,需要寄存一拍。



总结:

1、时序逻辑:非阻塞赋值,组合逻辑:阻塞赋值(官方推荐)
2、always语句块中不要即使用阻塞赋值,又使用非阻塞赋值
3、锁存器不推荐使用,使用时要用非阻塞赋值
4、一个always语句块只对一个变量赋值

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐