parent
d3f608058f
commit
a05cbd8382
1
Changes
1
Changes
|
|
@ -18,6 +18,7 @@ Verilator 5.045 devel
|
|||
* Add parsing of solve-before inside foreach (#6934). [Pawel Kojma, Antmicro Ltd.]
|
||||
* Add error when accessing a non-static class field from a static function (#6948). [Artur Bieniek, Antmicro Ltd.]
|
||||
* Add VerilatedContext::useNumaAssign and set on threads() call (#6954). [Yangyu Chen]
|
||||
* Support structure initial values (#6130).
|
||||
* Support vpi_put/vpi_get forcing of signals (#5933) (#6704). [Christian Hecken]
|
||||
* Support detailed failure info for constraint violations (#6617) (#6883). [Yilou Wang]
|
||||
* Support `unique` constraints (on 1D static arrays) (#6810) (#6878). [Srinivasan Venkataramanan]
|
||||
|
|
|
|||
|
|
@ -542,6 +542,8 @@ void EmitCFunc::emitVarReset(AstVar* varp, bool constructing) {
|
|||
// If an ARRAYINIT we initialize it using an initial block similar to a signal
|
||||
// puts("// parameter "+varp->nameProtect()+" = "+varp->valuep()->name()+"\n");
|
||||
} else if (const AstInitArray* const initarp = VN_CAST(varp->valuep(), InitArray)) {
|
||||
// TODO this code probably better handled as initp argument to emitVarResetRecurse
|
||||
// TODO merge this functionality with V3EmitCConstInit.h visitors
|
||||
if (VN_IS(dtypep, AssocArrayDType)) {
|
||||
if (initarp->defaultp()) {
|
||||
emitSetVarConstant(varNameProtected + ".atDefault()",
|
||||
|
|
@ -583,13 +585,14 @@ void EmitCFunc::emitVarReset(AstVar* varp, bool constructing) {
|
|||
varp->v3fatalSrc("InitArray under non-arrayed var");
|
||||
}
|
||||
} else {
|
||||
putns(varp, emitVarResetRecurse(varp, constructing, varNameProtected, dtypep, 0, ""));
|
||||
putns(varp, emitVarResetRecurse(varp, constructing, varNameProtected, dtypep, 0, "",
|
||||
varp->valuep()));
|
||||
}
|
||||
}
|
||||
|
||||
string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
||||
const string& varNameProtected, AstNodeDType* dtypep,
|
||||
int depth, const string& suffix) {
|
||||
int depth, const string& suffix, const AstNode* valuep) {
|
||||
dtypep = dtypep->skipRefp();
|
||||
AstBasicDType* const basicp = dtypep->basicp();
|
||||
// Returns string to do resetting, empty to do nothing (which caller should handle)
|
||||
|
|
@ -599,14 +602,14 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
|||
const string pre = constructing ? "" : varNameProtected + suffix + ".clear();\n";
|
||||
return pre
|
||||
+ emitVarResetRecurse(varp, constructing, varNameProtected, adtypep->subDTypep(),
|
||||
depth + 1, suffix + ".atDefault()" + cvtarray);
|
||||
depth + 1, suffix + ".atDefault()" + cvtarray, nullptr);
|
||||
} else if (AstWildcardArrayDType* const adtypep = VN_CAST(dtypep, WildcardArrayDType)) {
|
||||
// Access std::array as C array
|
||||
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
|
||||
const string pre = constructing ? "" : varNameProtected + suffix + ".clear();\n";
|
||||
return pre
|
||||
+ emitVarResetRecurse(varp, constructing, varNameProtected, adtypep->subDTypep(),
|
||||
depth + 1, suffix + ".atDefault()" + cvtarray);
|
||||
depth + 1, suffix + ".atDefault()" + cvtarray, nullptr);
|
||||
} else if (VN_IS(dtypep, CDType)) {
|
||||
return ""; // Constructor does it
|
||||
} else if (VN_IS(dtypep, ClassRefDType)) {
|
||||
|
|
@ -619,14 +622,14 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
|||
const string pre = constructing ? "" : varNameProtected + suffix + ".clear();\n";
|
||||
return pre
|
||||
+ emitVarResetRecurse(varp, constructing, varNameProtected, adtypep->subDTypep(),
|
||||
depth + 1, suffix + ".atDefault()" + cvtarray);
|
||||
depth + 1, suffix + ".atDefault()" + cvtarray, nullptr);
|
||||
} else if (const AstQueueDType* const adtypep = VN_CAST(dtypep, QueueDType)) {
|
||||
// Access std::array as C array
|
||||
const string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : "");
|
||||
const string pre = constructing ? "" : varNameProtected + suffix + ".clear();\n";
|
||||
return pre
|
||||
+ emitVarResetRecurse(varp, constructing, varNameProtected, adtypep->subDTypep(),
|
||||
depth + 1, suffix + ".atDefault()" + cvtarray);
|
||||
depth + 1, suffix + ".atDefault()" + cvtarray, nullptr);
|
||||
} else if (VN_IS(dtypep, SampleQueueDType)) {
|
||||
return "";
|
||||
} else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
|
||||
|
|
@ -637,17 +640,17 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
|||
+ cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n");
|
||||
const string below
|
||||
= emitVarResetRecurse(varp, constructing, varNameProtected, adtypep->subDTypep(),
|
||||
depth + 1, suffix + "[" + ivar + "]");
|
||||
depth + 1, suffix + "[" + ivar + "]", nullptr);
|
||||
const string post = "}\n";
|
||||
return below.empty() ? "" : pre + below + post;
|
||||
} else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) {
|
||||
const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
|
||||
const AstNodeUOrStructDType* const sdtypep = VN_AS(dtypep, NodeUOrStructDType);
|
||||
string literal;
|
||||
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
const std::string line = emitVarResetRecurse(
|
||||
varp, constructing, varNameProtected + suffix + "." + itemp->nameProtect(),
|
||||
itemp->dtypep(), depth + 1, "");
|
||||
itemp->dtypep(), depth + 1, "", itemp->valuep());
|
||||
if (!line.empty()) literal += line;
|
||||
}
|
||||
return literal;
|
||||
|
|
@ -682,10 +685,10 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
|||
splitSizeInc(1);
|
||||
if (dtypep->isWide()) { // Handle unpacked; not basicp->isWide
|
||||
string out;
|
||||
if (varp->valuep()) {
|
||||
const AstConst* const constp = VN_AS(varp->valuep(), Const);
|
||||
if (valuep) {
|
||||
const AstConst* const constp = VN_AS(valuep, Const);
|
||||
UASSERT_OBJ(constp, varp, "non-const initializer for variable");
|
||||
for (int w = 0; w < varp->widthWords(); ++w) {
|
||||
for (int w = 0; w < dtypep->widthWords(); ++w) {
|
||||
out += varNameProtected + suffix + "[" + cvtToStr(w) + "] = ";
|
||||
out += cvtToStr(constp->num().edataWord(w)) + "U;\n";
|
||||
}
|
||||
|
|
@ -709,7 +712,15 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
|||
return out;
|
||||
} else {
|
||||
string out = varNameProtected + suffix;
|
||||
if (zeroit) {
|
||||
if (valuep) {
|
||||
out += " = ";
|
||||
// TODO cleanup code shared between here, V3EmitCConstInit.h,
|
||||
// EmitCFunc::emitVarReset, EmitCFunc::emitConstant
|
||||
const AstConst* const constp = VN_AS(valuep, Const);
|
||||
UASSERT_OBJ(constp, varp, "non-const initializer for variable");
|
||||
out += cvtToStr(constp->num().edataWord(0)) + "U;\n";
|
||||
out += ";\n";
|
||||
} else if (zeroit) {
|
||||
out += " = 0;\n";
|
||||
} else {
|
||||
emitVarResetScopeHash();
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ public:
|
|||
void emitVarReset(AstVar* varp, bool constructing);
|
||||
string emitVarResetRecurse(const AstVar* varp, bool constructing,
|
||||
const string& varNameProtected, AstNodeDType* dtypep, int depth,
|
||||
const string& suffix);
|
||||
const string& suffix, const AstNode* valuep);
|
||||
void emitVarResetScopeHash();
|
||||
void emitChangeDet();
|
||||
void emitConstInit(AstNode* initp) { iterateConst(initp); }
|
||||
|
|
|
|||
|
|
@ -3270,10 +3270,6 @@ class WidthVisitor final : public VNVisitor {
|
|||
itemp->v3error("Initial values not allowed in packed struct/union"
|
||||
" (IEEE 1800-2023 7.2.2)");
|
||||
pushDeletep(itemp->valuep()->unlinkFrBack());
|
||||
} else if (itemp->valuep()) {
|
||||
itemp->valuep()->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Initial values in struct/union members");
|
||||
pushDeletep(itemp->valuep()->unlinkFrBack());
|
||||
}
|
||||
}
|
||||
const bool isHardPackedUnion
|
||||
|
|
@ -5146,6 +5142,11 @@ class WidthVisitor final : public VNVisitor {
|
|||
// default_value for any unmatched member yet
|
||||
return defaultp->cloneTree(false);
|
||||
}
|
||||
if (memp->valuep()) {
|
||||
return new AstPatMember{nodep->fileline(),
|
||||
VN_AS(memp->valuep()->cloneTree(false), NodeExpr),
|
||||
new AstText{nodep->fileline(), memp->name()}, nullptr};
|
||||
}
|
||||
if (!VN_IS(memp_vdtypep, UnionDType)) {
|
||||
nodep->v3error("Assignment pattern missed initializing elements: "
|
||||
<< memp->virtRefDTypep()->prettyDTypeNameQ() << " "
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
%Error-UNSUPPORTED: t/t_struct_unpacked_init.v:12:24: Unsupported: Initial values in struct/union members
|
||||
: ... note: In instance 't'
|
||||
12 | bit [3:0] m_lo = P;
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
|
|
@ -4,13 +4,15 @@
|
|||
# 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-FileCopyrightText: 2024 Wilson Snyder
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -1,25 +1,40 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2023 Wilson Snyder
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t;
|
||||
|
||||
parameter P = 4'h5;
|
||||
parameter P = 4'h5;
|
||||
|
||||
struct { // Can't legally be packed
|
||||
bit [3:0] m_lo = P;
|
||||
bit [3:0] m_hi;
|
||||
} s;
|
||||
typedef struct { // Must be unpacked -- existing error check
|
||||
// Update ctor_var_reset to check instead of making a constructor
|
||||
bit [3:0] m_lo = P;
|
||||
bit [93:0] m_mid = '1; // Wide
|
||||
bit [3:0] m_hi;
|
||||
} s_t;
|
||||
s_t s;
|
||||
|
||||
initial begin
|
||||
s.m_hi = 4'ha;
|
||||
if (s.m_lo != 4'h5) $stop;
|
||||
if (s.m_hi != 4'ha) $stop;
|
||||
initial begin
|
||||
$display("%p", s);
|
||||
`checkh(s.m_lo, 4'h5);
|
||||
`checkh(s.m_mid, ~94'h0);
|
||||
`checkh(s.m_hi, 4'h0);
|
||||
s.m_mid = 94'ha;
|
||||
s.m_hi = 4'hb;
|
||||
$display("%p", s);
|
||||
`checkh(s.m_lo, 4'h5);
|
||||
`checkh(s.m_mid, 94'ha);
|
||||
`checkh(s.m_hi, 4'hb);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t;
|
||||
|
||||
parameter P = 4'h5;
|
||||
|
||||
typedef struct { // Must be unpacked -- existing error check
|
||||
bit [3:0] m_lo = P;
|
||||
bit [93:0] m_mid = '1; // Wide
|
||||
bit [3:0] m_hi;
|
||||
} s_t;
|
||||
|
||||
localparam s_t S = '{m_hi: 6}; // Not setting m_mid/m_hi
|
||||
|
||||
localparam S_LO = S.m_lo;
|
||||
localparam S_HI = S.m_hi;
|
||||
|
||||
initial begin
|
||||
`checkh(S.m_hi, 4'h6);
|
||||
`checkh(S_HI, 4'h6);
|
||||
|
||||
`checkh(S.m_lo, 4'h5);
|
||||
`checkh(S_LO, 4'h5);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue