Verilog: 如何将输入信号延迟一个时钟周期?

3
我希望将输入信号延迟一个完整的时钟周期。
我有下面的代码,基本上尝试在时钟的posedge处更改信号。
但是,测试台显示它并不总是延迟1个周期。
在某些情况下,它会在输入信号更改的同时更改。
是否有任何解决此类问题的方法?
module delay_one_cycle(
  input clk,
  input[3:0] original_signal,
  output reg[3:0] delayed_signal
);

  always @(posedge clk) begin
    delayed_signal <= original_signal;
  end


endmodule

module delay_one_cycle_tb();
  reg clk;
  reg[3:0] original_signal;  
  wire[3:0] delayed_signal;

  delay_one_cycle doc_inst (clk, original_signal, delayed_signal);  

  // Initial setup
  initial begin  
    clk                 = 0;

    original_signal     = 4'd9;
    #5 original_signal  = 4'd10;
    #5 original_signal  = 4'd11;    
    #4 original_signal  = 4'd12;
    #3 original_signal  = 4'd13;

    // finish the simulation
    #5 $finish;
  end  

  // clock
  always begin
    #1 clk = !clk;
  end
endmodule

这是波形图: enter image description here 该波形图显示了输入信号在时钟边沿变为1010时,输出也同时发生变化。
但是,延迟信号实际上并没有延迟到下一个周期!
3个回答

4
这个问题与您的问题「为什么我的D触发器不等待时钟的正沿?」非常相似。
您可能希望尝试以下惯例以避免竞态条件:
@(posedge clk);

尽量避免使用阻塞分配将输入信号设置到RTL代码中。如@Morten Zilmer所建议的那样,使用非阻塞分配。

您的测试台应该类似于这样:

module delay_one_cycle(
  input clk,
  input[3:0] original_signal,
  output reg[3:0] delayed_signal
);

  always @(posedge clk) begin
    delayed_signal <= original_signal;
  end


endmodule

module delay_one_cycle_tb();
  reg clk;
  reg[3:0] original_signal;  
  wire[3:0] delayed_signal;

  delay_one_cycle doc_inst (clk, original_signal, delayed_signal);  

  // Initial setup
  initial begin  

    original_signal     <= 4'd9;
    repeat (5) @(posedge clk);
    original_signal  <= 4'd10;
    repeat (5) @(posedge clk);
    original_signal  <= 4'd11;
    repeat (4) @(posedge clk);
    original_signal  <= 4'd12;
    repeat (3) @(posedge clk);
    original_signal  <= 4'd13;

    // finish the simulation
   repeat (5) @(posedge clk);
   $finish;
  end  

  initial begin
    clk                 = 0;
    forever begin
       #1 clk = !clk;
    end
  end 
endmodule

希望这能帮到您。

3

问题是一个Verilog竞争条件

因此,在发生clk上升沿的同时更改original_signal时,original_signal在基于clk的更新之前获得新值,结果是您无法获得所需的延迟。

always块中使用非阻塞赋值(<=)而不是阻塞赋值(=)。

另外,使用clk来控制刺激数据的变化,使用repeat (5) @(posedge clk);,以便获得顺序设计的强大测试台。

在上面的搜索和Verilog综合中的非阻塞赋值中了解更多有关此问题的信息。


  1. 单个语句@(posedge clk);的作用是什么?我只见过这样的语法:always @ (posedge clk) begin .... end。
  2. 它是什么类型的结构,如何与上面的repeat配合使用?例如:repeat (5) @(posedge clk);
  3. 在上述代码中,是否需要同时使用repeat (5) @(posedge clk);和非阻塞赋值(<=)才能获得正确的模拟结果?
- user3330840

0
这可能是因为在改变输入数据的瞬间,输出值也会发生变化,但根据你的测试台,例如将值更改为4'd11发生在时钟的负边沿。因此,在原始模块中,always块直到时钟的正边沿才被执行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接