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 в исходном модуле не вводится до положения часов.