Почему мой D-флип-флоп не ждет положительного перевеса часов?
Как я знаю, D flipflop производит выборку своего входного значения на каждом положительном фронте тактовой частоты.
Таким образом, будет произведена задержка в 1 цикл. Правильно?
Но почему мой D-триггер не производит задержку в 1 цикл?
module flipflop(
input clk,
input rstn,
input [7:0] i_data,
output reg [7:0] o_data
);
always @(posedge clk) begin
if (~rstn) begin
o_data <= 0;
end
else begin
o_data <= i_data;
end
end
endmodule
module test;
reg clk;
reg [7:0] i_data;
reg rstn;
wire [7:0] o_data;
initial begin
clk = 0;
rstn = 1;
i_data = 0;
#20;
rstn = 0;
#30;
rstn = 1;
#20;
i_data = 8'hFA;
#20;
i_data = 8'hF0;
#20
i_data = 8'hF1;
#20
#10 $finish;
end
always #10 clk = !clk;
flipflop flipflop(
.clk (clk),
.rstn(rstn),
.i_data(i_data),
.o_data(o_data)
);
initial begin
$dumpfile("flipflop.vcd");
$dumpvars();
end
endmodule
Мой D-триггер здесь работает как комбинационная схема.
2 ответа
Симулятор, вероятно, делает что-то вроде этого:
initial begin
clk = 0;
rstn = 1;
i_data = 0;
#10;
clk = !clk;
#10;
rstn = 0;
clk = !clk;
#10;
clk = !clk;
#10;
clk = !clk;
#10;
rstn = 1;
clk = !clk;
#10;
clk = !clk;
#10
i_data = 8'hFA; //Input updated
clk = !clk; //Clock event
//o_data assigned here
#10;
clk = !clk;
#10;
i_data = 8'hF0;
clk = !clk;
#20
i_data = 8'hF1;
#20
#10 $finish;
end
Поскольку событие часов происходит последним на каждом шаге по времени от вашего стенда, похоже, что флоп назначается немедленно. Вероятно, вы хотите, чтобы ваш тестовый стенд был полностью подчинен, поэтому предложение Марти об использовании @(posedge...) позволит добиться этого. Вы также можете просто отложить свои назначения один раз в самом начале:
initial begin
clk = 0;
#1;
rstn = 1;
i_data = 0;
#20;
rstn = 0;
#30;
rstn = 1;
#20;
i_data = 8'hFA;
#20;
i_data = 8'hF0;
#20
i_data = 8'hF1;
#20
#10 $finish;
end
Вы столкнулись с тонкостями планирования событий симулятора Verilog! Изменение назначений данных для использования неблокирующих назначений, вероятно, является самым простым решением.
#20;
i_data <= 8'hFA;
#20;
i_data <= 8'hF0;
#20
i_data <= 8'hF1;
#20
Что происходило в вашей оригинальной версии, так это то, что часы и входные данные были запланированы для одновременного использования. Так как симулятор может делать только одну вещь за один раз, он должен решить, будет ли он сначала менять часы или данные. Сначала он изменил данные, поэтому, когда наступает фронт тактовых импульсов, входные данные уже изменились на следующее значение, поэтому похоже, что данные проскальзывают через FF.
Неблокирующие назначения (<=
) запланированы на выполнение после всех назначений блокировки (=
) было сделано. Таким образом, выполнение неблокирующих назначений данных гарантирует, что они произойдут после назначенных на блокировку фронтов тактов.
Еще один способ переписать вещи на работу:
initial begin
@(posedge clk) i_data = 8'hFA;
@(posedge clk) i_data = 8'hF0;
@(posedge clk) i_data = 8'hF1;
end