verilog 中的 DFF 有延迟
DFF in verilog with a delay
我正在尝试实施 nand2tetris project in verilog and am hitting a wall using icarus verilog。在书中,他们是这样实现 DFF 的,q(t) = d(t-1)
。当前时间的输出是前一个posedge clk
的输入。这是我实现的DFF
。
module Dff (
output reg q,
input data, clk
);
reg p;
reg o;
always @(posedge clk) begin
o <= data;
q <= p;
end
always @(negedge clk) begin
p <= o;
end
endmodule
这个DFF我直接测试的时候好像没问题。但是当我重新使用它来创建一个位(一个存储单元)时,它变得疯狂了。有趣的是,使用 Icarus Verilog 或 EDAPlayground(使用 VCS)的疯狂是不同的。
module Mux (out, a, b, sel);
input a, b;
input sel;
output reg out;
assign out = ~sel ? a : b;
endmodule
module Bit (
output out,
input data, load, clk
);
Mux m0(in, out, data, load);
Dff d0(out, in, clk);
endmodule
Icarus Verilog 输出
data | load | clk | out
------+------+-----+-----
0 | 1 | 1 | x
0 | 1 | 0 | x
1 | 1 | 1 | x
1 | 1 | 0 | x
0 | 1 | 1 | 1
0 | 1 | 0 | 1
0 | 0 | 1 | 0
0 | 0 | 0 | 0
1 | 1 | 1 | 0
1 | 1 | 0 | 0
0 | 0 | 1 | 0 # !?!?!
0 | 0 | 0 | 0 # it should be 1 here.
EDAPlayground 输出
data | load | clk | out
------+------+-----+-----
0 | 1 | 1 | x
0 | 1 | 0 | x
1 | 1 | 1 | x
1 | 1 | 0 | x
0 | 1 | 1 | 1
0 | 1 | 0 | 1
0 | 0 | 1 | 0
0 | 0 | 0 | 0
1 | 1 | 1 | 1 # !?!?!
1 | 1 | 0 | 1 # it should be 0 here.
0 | 0 | 1 | 1
0 | 0 | 0 | 1
代码可在 EDAPlayground 上测试。
感谢 Uun 和 Greg,这是我解决问题的方法。 code is on EDA playground
DFF 可以更简单。
module Dff (
output reg q,
input data, clk
);
always @(posedge clk) begin
q <= data;
end
endmodule
然后测试是罪魁祸首。阻塞分配导致混乱。解决这个问题的一个简单方法是将所有 =
更改为 <=
,如下所示:
module Bit_tb;
reg clk = 0;
reg data = 0;
reg load = 1;
wire out;
initial begin
#2
data <= 1;
#2
load <= 0; // load = 0; /!\ would be blocking before
data <= 0; // data = 0; doing this line. /!\
#2
$finish;
end
endmodule
我正在尝试实施 nand2tetris project in verilog and am hitting a wall using icarus verilog。在书中,他们是这样实现 DFF 的,q(t) = d(t-1)
。当前时间的输出是前一个posedge clk
的输入。这是我实现的DFF
。
module Dff (
output reg q,
input data, clk
);
reg p;
reg o;
always @(posedge clk) begin
o <= data;
q <= p;
end
always @(negedge clk) begin
p <= o;
end
endmodule
这个DFF我直接测试的时候好像没问题。但是当我重新使用它来创建一个位(一个存储单元)时,它变得疯狂了。有趣的是,使用 Icarus Verilog 或 EDAPlayground(使用 VCS)的疯狂是不同的。
module Mux (out, a, b, sel);
input a, b;
input sel;
output reg out;
assign out = ~sel ? a : b;
endmodule
module Bit (
output out,
input data, load, clk
);
Mux m0(in, out, data, load);
Dff d0(out, in, clk);
endmodule
Icarus Verilog 输出
data | load | clk | out
------+------+-----+-----
0 | 1 | 1 | x
0 | 1 | 0 | x
1 | 1 | 1 | x
1 | 1 | 0 | x
0 | 1 | 1 | 1
0 | 1 | 0 | 1
0 | 0 | 1 | 0
0 | 0 | 0 | 0
1 | 1 | 1 | 0
1 | 1 | 0 | 0
0 | 0 | 1 | 0 # !?!?!
0 | 0 | 0 | 0 # it should be 1 here.
EDAPlayground 输出
data | load | clk | out
------+------+-----+-----
0 | 1 | 1 | x
0 | 1 | 0 | x
1 | 1 | 1 | x
1 | 1 | 0 | x
0 | 1 | 1 | 1
0 | 1 | 0 | 1
0 | 0 | 1 | 0
0 | 0 | 0 | 0
1 | 1 | 1 | 1 # !?!?!
1 | 1 | 0 | 1 # it should be 0 here.
0 | 0 | 1 | 1
0 | 0 | 0 | 1
代码可在 EDAPlayground 上测试。
感谢 Uun 和 Greg,这是我解决问题的方法。 code is on EDA playground
DFF 可以更简单。
module Dff (
output reg q,
input data, clk
);
always @(posedge clk) begin
q <= data;
end
endmodule
然后测试是罪魁祸首。阻塞分配导致混乱。解决这个问题的一个简单方法是将所有 =
更改为 <=
,如下所示:
module Bit_tb;
reg clk = 0;
reg data = 0;
reg load = 1;
wire out;
initial begin
#2
data <= 1;
#2
load <= 0; // load = 0; /!\ would be blocking before
data <= 0; // data = 0; doing this line. /!\
#2
$finish;
end
endmodule