据我所知,D触发器在每个上升沿采样其输入值 时钟
因此,它将产生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触发器就像这里的组合电路一样。
答案 0 :(得分:5)
你遇到了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
答案 1 :(得分:5)
模拟器可能会做这样的事情:
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
由于时钟事件在您的测试平台的每个时间步骤中最后发生,所以看起来就像是立即分配了翻牌。您可能希望您的测试平台完全不受限制,因此Marty建议使用@(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