Fix X handling in UDPs (#6723)

This commit is contained in:
Michael Bikovitsky 2025-11-23 03:09:49 +02:00 committed by GitHub
parent 087ca15138
commit 9632c614be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 167 additions and 1 deletions

View File

@ -138,6 +138,12 @@ class UdpVisitor final : public VNVisitor {
fl, logandp, new AstLogNot{fl, new AstVarRef{fl, varp, VAccess::READ}}};
} else if (valName == "1" || valName == "r") {
logandp = new AstLogAnd{fl, logandp, new AstVarRef{fl, varp, VAccess::READ}};
} else if (valName == "x" || valName == "X") {
// No x inputs supported yet, so this whole table line
// can never match. Drop the whole thing.
if (edgetrigp) pushDeletep(edgetrigp);
if (logandp) pushDeletep(logandp);
return;
}
}
iNodep = iNodep->nextp();
@ -166,6 +172,12 @@ class UdpVisitor final : public VNVisitor {
} else if (oNodep->name() == "1") {
logandp
= new AstLogAnd{fl, logandp, new AstVarRef{fl, m_oFieldVarp, VAccess::READ}};
} else if (oNodep->name() == "x" || oNodep->name() == "X") {
// No x inputs supported yet, so this whole table line
// can never match. Drop the whole thing.
if (edgetrigp) pushDeletep(edgetrigp);
if (logandp) pushDeletep(logandp);
return;
}
}
@ -192,6 +204,7 @@ class UdpVisitor final : public VNVisitor {
void visit(AstLogNot* nodep) override { iterateChildren(nodep); }
// For logic processing.
bool isEdgeTrig(std::string& valName) {
if (valName == "x" || valName == "X") return false;
if (valName == "*") return true;
if (valName == "01" || valName == "p" || valName == "P" || valName == "r"
|| valName == "R") {
@ -204,7 +217,9 @@ class UdpVisitor final : public VNVisitor {
return true;
}
if (valName.size() == 2) {
if (valName[0] == '1' || valName[1] == '0')
if (valName[0] == 'x' || valName[0] == 'X' || valName[1] == 'x' || valName[1] == 'X')
valName = "x";
else if (valName[0] == '1' || valName[1] == '0')
valName = "f";
else if (valName[0] == '0' || valName[1] == '1')
valName = "r";

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('vlt_all')
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,49 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Michael Bikovitsky.
// SPDX-License-Identifier: CC0-1.0
module t ();
wire true1;
not1 a(true1, '0);
wire false1;
not1 b(false1, '1);
wire true2;
not1 c(true2, '0);
wire false2;
not1 d(false2, '1);
initial begin
if (true1 != '1) $stop;
if (false1 != '0) $stop;
if (true2 != '1) $stop;
if (false2 != '0) $stop;
$finish;
end
endmodule
primitive not1 (q, d);
output q;
input d;
table
0 : 1;
1 : 0;
x : x;
endtable
endprimitive
primitive not2 (q, d);
output q;
input d;
table
0 : 1;
1 : 0;
X : X;
endtable
endprimitive

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('vlt_all')
test.compile(verilator_flags2=["--x-assign", "1"])
test.execute()
test.passes()

View File

@ -0,0 +1,66 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Michael Bikovitsky.
// SPDX-License-Identifier: CC0-1.0
module t (
input wire clk
);
wire q1;
pos i_pos(q1, clk);
wire q2;
neg i_neg(q2, clk);
integer cycle = 0;
always @(posedge clk) begin
if (cycle == 10) $finish;
cycle <= cycle + 1;
end
always @(q1 or q2) begin
// q1 should be assigned to 0 on every posedge and to X otherwise.
// So when the value of q1 changes, *and* clk is positive, we expect
// q1 to be 1.
// Same for q2, but on the negedge.
if (clk && q1) $stop;
if (!clk && q2) $stop;
end
endmodule
primitive pos (q, clk);
output q;
reg q;
input clk;
table
(01) : ? : 0;
// Explicitly set the output to X on clk 0->X edge.
// This edge can never happen in Verilator.
// If all edges *from* 0 are treated as rising edges, this will cause
// the output to be 1, since we use --x-assign 1, and the test will fail.
// (Actually this depends on the evaluation order of the always blocks
// that V3Udp.cpp creates, but at the time of writing they seem to be
// evaluated in the order of the lines in the table.)
(0x) : ? : x;
endtable
endprimitive
primitive neg (q, clk);
output q;
reg q;
input clk;
table
(10) : ? : 0;
// Explicitly set the output to X on clk X->0 edge.
// This edge can never happen in Verilator.
// If all edges *to* 0 are treated as falling edges, this will cause
// the output to be 1, since we use --x-assign 1, and the test will fail.
// (Actually this depends on the evaluation order of the always blocks
// that V3Udp.cpp creates, but at the time of writing they seem to be
// evaluated in the order of the lines in the table.)
(x0) : ? : x;
endtable
endprimitive