Change array tracing to always dump left index to right index (#7205)

Also add array bounds and struct/union member counts to trace pushPrefix
(not used by vcd/fst/saif). Together these improve consistency in some
waveform formats.
This commit is contained in:
Geza Lore 2026-03-06 09:32:08 +00:00 committed by GitHub
parent b89d29cab9
commit cedec65c39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 58 additions and 21 deletions

View File

@ -148,8 +148,10 @@ public:
const char** itemNamesp, const char** itemValuesp); const char** itemNamesp, const char** itemValuesp);
}; };
// duck-typed interface to decl* methods // We use macros to drop unused arguments at compile time. This saves code size.
// We use macros in order to strip out unused args at compile time. #define VL_TRACE_PUSH_PREFIX(tracep, name, type, left, right) tracep->pushPrefix(name, type);
#define VL_TRACE_POP_PREFIX(tracep) tracep->popPrefix();
#define VL_TRACE_DECL_EVENT(tracep, code, fidx, name, dtypenum, dir, kind, type) \ #define VL_TRACE_DECL_EVENT(tracep, code, fidx, name, dtypenum, dir, kind, type) \
tracep->declEvent(code, name, dtypenum, dir, kind, type) tracep->declEvent(code, name, dtypenum, dir, kind, type)
#define VL_TRACE_DECL_BIT(tracep, code, fidx, name, dtypenum, dir, kind, type) \ #define VL_TRACE_DECL_BIT(tracep, code, fidx, name, dtypenum, dir, kind, type) \

View File

@ -166,8 +166,10 @@ public:
void declDoubleArray(uint32_t code, uint32_t fidx, const char* name, int arraynum); void declDoubleArray(uint32_t code, uint32_t fidx, const char* name, int arraynum);
}; };
// duck-typed interface to decl* methods // We use macros to drop unused arguments at compile time. This saves code size.
// We use macros in order to strip out unused args at compile time. #define VL_TRACE_PUSH_PREFIX(tracep, name, type, left, right) tracep->pushPrefix(name, type);
#define VL_TRACE_POP_PREFIX(tracep) tracep->popPrefix();
#define VL_TRACE_DECL_EVENT(tracep, code, fidx, name, dtypenum, dir, kind, type) \ #define VL_TRACE_DECL_EVENT(tracep, code, fidx, name, dtypenum, dir, kind, type) \
tracep->declEvent(code, fidx, name) tracep->declEvent(code, fidx, name)
#define VL_TRACE_DECL_BIT(tracep, code, fidx, name, dtypenum, dir, kind, type) \ #define VL_TRACE_DECL_BIT(tracep, code, fidx, name, dtypenum, dir, kind, type) \

View File

@ -154,8 +154,9 @@ public:
void declDoubleArray(uint32_t code, const char* name, int arraynum); void declDoubleArray(uint32_t code, const char* name, int arraynum);
}; };
// duck-typed interface to decl* methods // We use macros to drop unused arguments at compile time. This saves code size.
// We use macros in order to strip out unused args at compile time. #define VL_TRACE_PUSH_PREFIX(tracep, name, type, left, right) tracep->pushPrefix(name, type);
#define VL_TRACE_POP_PREFIX(tracep) tracep->popPrefix();
#define VL_TRACE_DECL_EVENT(tracep, code, fidx, name, dtypenum, dir, kind, type) \ #define VL_TRACE_DECL_EVENT(tracep, code, fidx, name, dtypenum, dir, kind, type) \
tracep->declEvent(code, name) tracep->declEvent(code, name)

View File

@ -1345,15 +1345,22 @@ public:
class AstTracePushPrefix final : public AstNodeStmt { class AstTracePushPrefix final : public AstNodeStmt {
const string m_prefix; // Prefix to add to signal names const string m_prefix; // Prefix to add to signal names
const VTracePrefixType m_prefixType; // Type of prefix being pushed const VTracePrefixType m_prefixType; // Type of prefix being pushed
const int m_left; // Array left index, or struct/union member count
const int m_right; // Array right index
public: public:
AstTracePushPrefix(FileLine* fl, const string& prefix, VTracePrefixType prefixType) AstTracePushPrefix(FileLine* fl, const string& prefix, VTracePrefixType prefixType,
int left = 0, int right = 0)
: ASTGEN_SUPER_TracePushPrefix(fl) : ASTGEN_SUPER_TracePushPrefix(fl)
, m_prefix{prefix} , m_prefix{prefix}
, m_prefixType{prefixType} {} , m_prefixType{prefixType}
, m_left{left}
, m_right{right} {}
ASTGEN_MEMBERS_AstTracePushPrefix; ASTGEN_MEMBERS_AstTracePushPrefix;
bool sameNode(const AstNode* samep) const override { return false; } bool sameNode(const AstNode* samep) const override { return false; }
string prefix() const { return m_prefix; } string prefix() const { return m_prefix; }
VTracePrefixType prefixType() const { return m_prefixType; } VTracePrefixType prefixType() const { return m_prefixType; }
int left() const { return m_left; }
int right() const { return m_right; }
}; };
class AstWait final : public AstNodeStmt { class AstWait final : public AstNodeStmt {
// @astgen op1 := condp : AstNodeExpr // @astgen op1 := condp : AstNodeExpr

View File

@ -682,7 +682,11 @@ class EmitCTrace final : public EmitCFunc {
// Array range // Array range
if (nodep->arrayRange().ranged()) { if (nodep->arrayRange().ranged()) {
puts(", (i+" + cvtToStr(nodep->arrayRange().lo()) + ")"); if (nodep->arrayRange().ascending()) {
puts(", (i + " + std::to_string(nodep->arrayRange().lo()) + ")");
} else {
puts(", (" + std::to_string(nodep->arrayRange().hi()) + " - i)");
}
} }
// Bit range // Bit range
@ -742,6 +746,10 @@ class EmitCTrace final : public EmitCFunc {
: "(oldp+"); : "(oldp+");
puts(cvtToStr(code - nodep->baseCode())); puts(cvtToStr(code - nodep->baseCode()));
puts(","); puts(",");
const VNumRange& arrayRange = nodep->declp()->arrayRange();
if (arrayRange.ranged() && !arrayRange.ascending()) {
arrayindex = arrayRange.elements() - 1 - arrayindex;
}
emitTraceValue(nodep, arrayindex); emitTraceValue(nodep, arrayindex);
if (emitWidth) puts("," + cvtToStr(nodep->declp()->widthMin())); if (emitWidth) puts("," + cvtToStr(nodep->declp()->widthMin()));
puts(");\n"); puts(");\n");
@ -802,14 +810,16 @@ class EmitCTrace final : public EmitCFunc {
EmitCFunc::visit(nodep); EmitCFunc::visit(nodep);
} }
void visit(AstTracePushPrefix* nodep) override { void visit(AstTracePushPrefix* nodep) override {
putns(nodep, "tracep->pushPrefix("); putns(nodep, "VL_TRACE_PUSH_PREFIX(tracep, ");
putsQuoted(VIdProtect::protectWordsIf(nodep->prefix(), nodep->protect())); putsQuoted(VIdProtect::protectWordsIf(nodep->prefix(), nodep->protect()));
puts(", VerilatedTracePrefixType::"); puts(", VerilatedTracePrefixType::");
puts(nodep->prefixType().ascii()); puts(nodep->prefixType().ascii());
puts(", " + std::to_string(nodep->left()));
puts(", " + std::to_string(nodep->right()));
puts(");\n"); puts(");\n");
} }
void visit(AstTracePopPrefix* nodep) override { // void visit(AstTracePopPrefix* nodep) override { //
putns(nodep, "tracep->popPrefix();\n"); putns(nodep, "VL_TRACE_POP_PREFIX(tracep);\n");
} }
void visit(AstTraceDecl* nodep) override { void visit(AstTraceDecl* nodep) override {
const int enumNum = emitTraceDeclDType(nodep->dtypep()); const int enumNum = emitTraceDeclDType(nodep->dtypep());

View File

@ -574,7 +574,8 @@ class TraceDeclVisitor final : public VNVisitor {
VL_RESTORER(m_traName); VL_RESTORER(m_traName);
FileLine* const flp = nodep->fileline(); FileLine* const flp = nodep->fileline();
addToSubFunc(new AstTracePushPrefix{flp, m_traName, VTracePrefixType::ARRAY_UNPACKED}); addToSubFunc(new AstTracePushPrefix{flp, m_traName, VTracePrefixType::ARRAY_UNPACKED,
nodep->left(), nodep->right()});
if (VN_IS(nodep->subDTypep()->skipRefToEnump(), if (VN_IS(nodep->subDTypep()->skipRefToEnump(),
BasicDType) // Nothing lower than this array BasicDType) // Nothing lower than this array
@ -589,7 +590,9 @@ class TraceDeclVisitor final : public VNVisitor {
} }
} else { } else {
AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump(); AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump();
for (int i = nodep->lo(); i <= nodep->hi(); ++i) { // Always iterate left index to right index
const int inc = nodep->rangep()->ascending() ? 1 : -1;
for (int i = nodep->left(); i != nodep->right() + inc; i += inc) {
VL_RESTORER(m_traValuep); VL_RESTORER(m_traValuep);
m_traName = '[' + std::to_string(i) + ']'; m_traName = '[' + std::to_string(i) + ']';
m_traValuep = m_traValuep->cloneTree(false); m_traValuep = m_traValuep->cloneTree(false);
@ -615,10 +618,14 @@ class TraceDeclVisitor final : public VNVisitor {
VL_RESTORER(m_traName); VL_RESTORER(m_traName);
FileLine* const flp = nodep->fileline(); FileLine* const flp = nodep->fileline();
addToSubFunc(new AstTracePushPrefix{flp, m_traName, VTracePrefixType::ARRAY_PACKED});
addToSubFunc(new AstTracePushPrefix{flp, m_traName, VTracePrefixType::ARRAY_PACKED,
nodep->left(), nodep->right()});
AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump(); AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump();
for (int i = nodep->lo(); i <= nodep->hi(); ++i) { // Always iterate left index to right index
const int inc = nodep->rangep()->ascending() ? 1 : -1;
for (int i = nodep->left(); i != nodep->right() + inc; i += inc) {
VL_RESTORER(m_traValuep); VL_RESTORER(m_traValuep);
m_traName = '[' + std::to_string(i) + ']'; m_traName = '[' + std::to_string(i) + ']';
const int lsb = (i - nodep->lo()) * subtypep->width(); const int lsb = (i - nodep->lo()) * subtypep->width();
@ -645,9 +652,12 @@ class TraceDeclVisitor final : public VNVisitor {
VL_RESTORER(m_traName); VL_RESTORER(m_traName);
FileLine* const flp = nodep->fileline(); FileLine* const flp = nodep->fileline();
int nMembers = 0;
for (AstNode* mp = nodep->membersp(); mp; mp = mp->nextp()) ++nMembers;
if (!nodep->packed()) { if (!nodep->packed()) {
addToSubFunc( addToSubFunc(new AstTracePushPrefix{flp, m_traName, //
new AstTracePushPrefix{flp, m_traName, VTracePrefixType::STRUCT_UNPACKED}); VTracePrefixType::STRUCT_UNPACKED, nMembers});
for (const AstMemberDType *itemp = nodep->membersp(), *nextp; itemp; itemp = nextp) { for (const AstMemberDType *itemp = nodep->membersp(), *nextp; itemp; itemp = nextp) {
nextp = VN_AS(itemp->nextp(), MemberDType); nextp = VN_AS(itemp->nextp(), MemberDType);
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefToEnump(); AstNodeDType* const subtypep = itemp->subDTypep()->skipRefToEnump();
@ -661,7 +671,8 @@ class TraceDeclVisitor final : public VNVisitor {
} }
addToSubFunc(new AstTracePopPrefix{flp}); addToSubFunc(new AstTracePopPrefix{flp});
} else { } else {
addToSubFunc(new AstTracePushPrefix{flp, m_traName, VTracePrefixType::STRUCT_PACKED}); addToSubFunc(new AstTracePushPrefix{flp, m_traName, //
VTracePrefixType::STRUCT_PACKED, nMembers});
for (const AstMemberDType *itemp = nodep->membersp(), *nextp; itemp; itemp = nextp) { for (const AstMemberDType *itemp = nodep->membersp(), *nextp; itemp; itemp = nextp) {
nextp = VN_AS(itemp->nextp(), MemberDType); nextp = VN_AS(itemp->nextp(), MemberDType);
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefToEnump(); AstNodeDType* const subtypep = itemp->subDTypep()->skipRefToEnump();
@ -690,10 +701,14 @@ class TraceDeclVisitor final : public VNVisitor {
VL_RESTORER(m_traName); VL_RESTORER(m_traName);
FileLine* const flp = nodep->fileline(); FileLine* const flp = nodep->fileline();
int nMembers = 0;
for (AstNode* mp = nodep->membersp(); mp; mp = mp->nextp()) ++nMembers;
if (!nodep->packed()) { if (!nodep->packed()) {
addIgnore("Unsupported: Unpacked union"); addIgnore("Unsupported: Unpacked union");
} else { } else {
addToSubFunc(new AstTracePushPrefix{flp, m_traName, VTracePrefixType::UNION_PACKED}); addToSubFunc(new AstTracePushPrefix{flp, m_traName, //
VTracePrefixType::UNION_PACKED, nMembers});
for (const AstMemberDType *itemp = nodep->membersp(), *nextp; itemp; itemp = nextp) { for (const AstMemberDType *itemp = nodep->membersp(), *nextp; itemp; itemp = nextp) {
nextp = VN_AS(itemp->nextp(), MemberDType); nextp = VN_AS(itemp->nextp(), MemberDType);
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefToEnump(); AstNodeDType* const subtypep = itemp->subDTypep()->skipRefToEnump();

View File

@ -2569,7 +2569,7 @@ class VlTest:
var = [] var = []
for line in fh: for line in fh:
match1 = re.search(r'\$scope (module|struct|interface)\s+(\S+)', line) match1 = re.search(r'\$scope (module|struct|interface)\s+(\S+)', line)
match2 = re.search(r'(\$var (\S+)\s+\d+\s+)\S+\s+(\S+)', line) match2 = re.search(r'(\$var \S+\s+\d+\s+)\S+\s+(.+)\s+\$end', line)
match3 = re.search(r'(\$attrbegin .* \$end)', line) match3 = re.search(r'(\$attrbegin .* \$end)', line)
line = line.rstrip() line = line.rstrip()
# print("VR"+ ' '*len(hier_stack) +" L " + line) # print("VR"+ ' '*len(hier_stack) +" L " + line)
@ -2583,7 +2583,7 @@ class VlTest:
# print("VR"+ ' '*len(hier_stack) +" var " + line) # print("VR"+ ' '*len(hier_stack) +" var " + line)
scope = '.'.join(hier_stack) scope = '.'.join(hier_stack)
var = match2.group(2) var = match2.group(2)
data[scope + "." + var] = match2.group(1) + match2.group(3) data[scope + "." + var] = match2.group(1)
elif match3: # $attrbegin elif match3: # $attrbegin
# print("VR"+ ' '*len(hier_stack) +" attr " + line) # print("VR"+ ' '*len(hier_stack) +" attr " + line)
if var: if var: