为什么输出处于未知状态?
Why output is in unknown state?
我想使用基于 的异步重置的 dff 和连续分配来制作一个串行比较器。但输出将进入未知 (x) 状态,我不知道为什么。我检查了每根电线并为它们分配了一个表达式
dff 代码(verilog):
module comparator (input a, input b, input reset, input clk, output [1:0] o);
wire q0_p, q0_n, q1_p, q1_n, d0, d1;
wire s0, r0, w01, w02, s1, r1, w11, w12;
assign d0 = (q1_n & q0_p) | (q0_p & ~a & b) | (q1_n & ~a & b);
assign d1 = (q1_p & q0_n) | (q0_n & a & ~b) | (q1_p & a & ~b);
assign w01 = ~(w02 & s0);
assign s0 = ~(w01 & reset & clk);
assign r0 = ~(s0 & clk & w02);
assign w02 = ~(r0 & d0 & reset);
assign q0_p = ~(s0 & q0_n);
assign q0_n = ~(q0_p & r0 & reset);
assign w11 = ~(w12 & s1);
assign s1 = ~(w11 & reset & clk);
assign r1 = ~(s1 & clk & w12);
assign w12 = ~(r1 & d1 & reset);
assign q1_p = ~(s1 & q1_n);
assign q1_n = ~(q1_p & r1 & reset);
assign o[0] = q0_p;
assign o[1] = q1_p;
endmodule
测试平台:
module test();
reg a, b, reset, clk = 0;
wire [1:0] o;
comparator cmp(a, b, reset, clk, o);
always #1 clk <= ~clk;
initial begin
$monitor("%b %b %b", a, b, o);
reset = 0;
reset = 1;
// a = 1110, b = 1011
#1 a = 1; b = 1;
#1 a = 1; b = 0;
#1 a = 1; b = 1;
#1 a = 0; b = 1;
$finish();
end
endmodule
输出:
1 1 xx
1 0 xx
1 1 xx
0 1 xx
如果 'D' 处于 'x' 状态,一旦您解除复位,输出将再次变为 'x'。在解除断言之前,您需要将一个已知值设置为 'D'。此外,您需要在复位断言和取消断言之间有延迟。
例如,
initial begin
$monitor("%b %b %b", a, b, o);
reset = 0;
#1
a = 0; b = 0;
reset = 1;
...
如您所见,在尝试对具有门级反馈的逻辑电路建模时调试仿真问题并非易事。你得到未知数 (x
) 因为你没有正确初始化所有需要初始化的信号。
您的测试台并没有真正将复位信号驱动为 0,因为您立即将其驱动为 1(两者都发生在时间 0)。您应该在 2 个值之间添加延迟。但是,这仍然不足以初始化所有信号。
解决方案是为您的逻辑使用适当的模型:行为级别。这在 Verilog 中是微不足道的。使用异步低电平有效复位模拟 dff 的常用方法是:
always @(posedge clk or negedge nreset) begin
if (!nreset) begin
q <= 1'b0;
end else begin
q <= d;
end
end
数字设计和 Verilog 的美妙之处在于您可以抽象掉所有不必要的细节。上面的代码消除了正确初始化所有信号的所有问题。
我想使用基于
dff 代码(verilog):
module comparator (input a, input b, input reset, input clk, output [1:0] o);
wire q0_p, q0_n, q1_p, q1_n, d0, d1;
wire s0, r0, w01, w02, s1, r1, w11, w12;
assign d0 = (q1_n & q0_p) | (q0_p & ~a & b) | (q1_n & ~a & b);
assign d1 = (q1_p & q0_n) | (q0_n & a & ~b) | (q1_p & a & ~b);
assign w01 = ~(w02 & s0);
assign s0 = ~(w01 & reset & clk);
assign r0 = ~(s0 & clk & w02);
assign w02 = ~(r0 & d0 & reset);
assign q0_p = ~(s0 & q0_n);
assign q0_n = ~(q0_p & r0 & reset);
assign w11 = ~(w12 & s1);
assign s1 = ~(w11 & reset & clk);
assign r1 = ~(s1 & clk & w12);
assign w12 = ~(r1 & d1 & reset);
assign q1_p = ~(s1 & q1_n);
assign q1_n = ~(q1_p & r1 & reset);
assign o[0] = q0_p;
assign o[1] = q1_p;
endmodule
测试平台:
module test();
reg a, b, reset, clk = 0;
wire [1:0] o;
comparator cmp(a, b, reset, clk, o);
always #1 clk <= ~clk;
initial begin
$monitor("%b %b %b", a, b, o);
reset = 0;
reset = 1;
// a = 1110, b = 1011
#1 a = 1; b = 1;
#1 a = 1; b = 0;
#1 a = 1; b = 1;
#1 a = 0; b = 1;
$finish();
end
endmodule
输出:
1 1 xx
1 0 xx
1 1 xx
0 1 xx
如果 'D' 处于 'x' 状态,一旦您解除复位,输出将再次变为 'x'。在解除断言之前,您需要将一个已知值设置为 'D'。此外,您需要在复位断言和取消断言之间有延迟。
例如,
initial begin
$monitor("%b %b %b", a, b, o);
reset = 0;
#1
a = 0; b = 0;
reset = 1;
...
如您所见,在尝试对具有门级反馈的逻辑电路建模时调试仿真问题并非易事。你得到未知数 (x
) 因为你没有正确初始化所有需要初始化的信号。
您的测试台并没有真正将复位信号驱动为 0,因为您立即将其驱动为 1(两者都发生在时间 0)。您应该在 2 个值之间添加延迟。但是,这仍然不足以初始化所有信号。
解决方案是为您的逻辑使用适当的模型:行为级别。这在 Verilog 中是微不足道的。使用异步低电平有效复位模拟 dff 的常用方法是:
always @(posedge clk or negedge nreset) begin
if (!nreset) begin
q <= 1'b0;
end else begin
q <= d;
end
end
数字设计和 Verilog 的美妙之处在于您可以抽象掉所有不必要的细节。上面的代码消除了正确初始化所有信号的所有问题。