Verilog: Как задержать входной сигнал на один такт?

Я хотел бы задержать входной сигнал на один полный тактовый цикл.
У меня есть код ниже, который в основном пытается изменить сигнал в позиции часов.
Однако тестовый стенд показывает, что он не всегда задерживается на 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

Вот форма волны: введите описание изображения здесь Форма сигнала показывает, например, когда входной сигнал изменяется на фронте тактового сигнала на 1010, выходной сигнал также изменяется одновременно.
задержанный сигнал фактически не откладывается до следующего цикла!

2 ответа

Решение

Этот вопрос очень похож на ваш вопрос. Почему мой D-Flip Flop не ждет положительного момента?

Вы можете попробовать это соглашение, чтобы избежать состояния гонки:

@(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

Надеюсь, это поможет.

Проблема в состоянии гонки Verilog.

Так что при смене original_signal в то же время, когда передний край clk происходит, то original_signal получает новое значение перед обновлением на основе clkи в результате вы не получите желаемую задержку.

Использовать неблокирующее назначение (<=) вместо блокировки назначить (=) в always блоки.

Также используйте clk контролировать изменение данных стимулов с repeat (5) @(posedge clk); как указывает @e19293001, чтобы получить надежный испытательный стенд для последовательного проектирования.

Подробнее об этой проблеме читайте в приведенном выше поиске и в разделе "Неблокирующие назначения в синтезе Verilog".

Это может быть связано с тем, что в тот момент, когда вы меняете входные данные, выходное значение изменяется, но, согласно вашему испытательному стенду, например, изменение значения на 4'd11 происходит незадолго до отсчета времени. Таким образом, блок always в исходном модуле не вводится до положения часов.

Другие вопросы по тегам