3
votes

I would like to delay an input signal by one complete clock cycle.
I have the code below which basically tries to change the signal at posedge of the clock.
However, the test bench shows that it doesn't always delay by 1 cycle.
In some cases, it changes at the same time the input signal changes.

Is there any way to solve this kind of problem?

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

Here is the waveform: enter image description here The waveform shows, for example, when input signal changes on the clock edge to 1010, output also changes at the same time.
the delayed_signal is not actually delayed to next cycle!

3

3 Answers

3
votes

This question is quite similar to your question Why is my D Flip Flop not waiting for the positive edge of the clock?

You might want to try this convention to avoid race condition:

@(posedge clk);

Try to avoid setting input signals to your RTL code with blocking assignments. Use non-blocking assignment instead as what @Morten Zilmer suggests.

Your test bench should somehow look something like this:

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

Hope that helps.

2
votes

Problem is a Verilog race condition.

So when changing original_signal at the same time where a rising edge of clk occurs, then original_signal gets the new value before update based on clk, and the result is that you don't get the desired delay.

Use non-blocking assign (<=) instead of blocking assign (=) in the always blocks.

Also use the clk to control change of stimuli data with repeat (5) @(posedge clk); as @e19293001 points out, in order to get a robust test bench for a sequential design.

Read more about the issue in the above search, and in this Nonblocking Assignments in Verilog Synthesis.

0
votes

This could be because the instant you change the input data, the output value changes, but according to your test bench, for example, changing the value to 4'd11 is happening at the negedge of the clock. So the always block in the original module is not entered till the posedge of the clock.