From 7fe51583e5025d368518e550efc3e4546bebb746 Mon Sep 17 00:00:00 2001 From: Yilou Wang Date: Tue, 11 Mar 2025 18:32:34 +0100 Subject: [PATCH] Fix foreach of assocArr inside a constraint block (#5727) (#5841) --- include/verilated.cpp | 15 +++++++++++++++ src/V3EmitCFunc.cpp | 3 ++- src/V3Randomize.cpp | 9 ++++++++- test_regress/t/t_constraint_assoc_arr_basic.v | 8 ++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 02333a810..12d2f1fb8 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -916,6 +917,20 @@ void _vl_vsformat(std::string& output, const std::string& format, va_list ap) VL } break; } + case 'p': { // 'x' but parameter is string + const int lbits = va_arg(ap, int); + const std::string* const cstr = va_arg(ap, const std::string*); + std::ostringstream oss; + for (unsigned char c : *cstr) { oss << std::hex << static_cast(c); } + std::string hex_str = oss.str(); + if (width > 0 && widthSet) { + hex_str = hex_str.size() > width + ? hex_str.substr(0, width) + : std::string(width - hex_str.size(), '0') + hex_str; + output += hex_str; + } + break; + } default: { // Deal with all read-and-print somethings const int lbits = va_arg(ap, int); diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 294fb3ab4..bbb139a2d 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -220,7 +220,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) { if (func != "") { puts(func); } else if (argp) { - const bool addrof = isScan || (fmt == '@'); + const bool addrof = isScan || (fmt == '@') || (fmt == 'p'); if (addrof) puts("&("); iterateConst(argp); if (!addrof) emitDatap(argp); @@ -371,6 +371,7 @@ void EmitCFunc::displayNode(AstNode* nodep, AstScopeName* scopenamep, const stri case 'o': displayArg(nodep, &elistp, isScan, vfmt, ignore, 'o'); break; case 'h': // FALLTHRU case 'x': displayArg(nodep, &elistp, isScan, vfmt, ignore, 'x'); break; + case 'p': displayArg(nodep, &elistp, isScan, vfmt, ignore, 'p'); break; case 's': displayArg(nodep, &elistp, isScan, vfmt, ignore, 's'); break; case 'e': displayArg(nodep, &elistp, isScan, vfmt, ignore, 'e'); break; case 'f': displayArg(nodep, &elistp, isScan, vfmt, ignore, 'f'); break; diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 109bc5248..bfdc88c8d 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -737,7 +737,14 @@ class ConstraintExprVisitor final : public VNVisitor { void visit(AstAssocSel* nodep) override { if (editFormat(nodep)) return; FileLine* const fl = nodep->fileline(); - if (VN_IS(nodep->bitp(), CvtPackString) && VN_IS(nodep->bitp()->dtypep(), BasicDType)) { + if (VN_IS(nodep->bitp(), VarRef) && VN_AS(nodep->bitp(), VarRef)->isString()) { + VNRelinker handle; + AstNodeExpr* const idxp + = new AstSFormatF{fl, "#x%32p", false, nodep->bitp()->unlinkFrBack(&handle)}; + handle.relink(idxp); + editSMT(nodep, nodep->fromp(), idxp); + } else if (VN_IS(nodep->bitp(), CvtPackString) + && VN_IS(nodep->bitp()->dtypep(), BasicDType)) { AstCvtPackString* const stringp = VN_AS(nodep->bitp(), CvtPackString); const size_t stringSize = VN_AS(stringp->lhsp(), Const)->width(); if (stringSize > 128) { diff --git a/test_regress/t/t_constraint_assoc_arr_basic.v b/test_regress/t/t_constraint_assoc_arr_basic.v index 1cd43562d..754b77221 100644 --- a/test_regress/t/t_constraint_assoc_arr_basic.v +++ b/test_regress/t/t_constraint_assoc_arr_basic.v @@ -8,6 +8,7 @@ class constrained_associative_array_basic; rand int int_index_arr [int]; rand int string_index_arr [string]; + rand int string_index_arr_2 [string]; /* verilator lint_off SIDEEFFECT */ // Constraints for both arrays constraint int_index_constraints { @@ -18,11 +19,15 @@ class constrained_associative_array_basic; string_index_arr["Bob"] inside {50, 60}; string_index_arr["Charlie"] > 25; } + constraint string_index_2_constraints { + foreach (string_index_arr_2[i]) string_index_arr_2[i] > 10; // nodep->bitp() would be VARREF, instead of CVTPACKSTRING + } // Constructor to initialize arrays function new(); int_index_arr = '{1: 0, 8: 0, 7: 0}; string_index_arr = '{"Alice": 25, "Bob": 50, "Charlie": 45}; + string_index_arr_2 = '{"key1": 15, "key2": 20, "key3": 30}; endfunction // Function to check and display the arrays @@ -35,6 +40,9 @@ class constrained_associative_array_basic; (name == "Bob" && !(string_index_arr[name] inside {50, 60})) || (name == "Charlie" && string_index_arr[name] <= 25)) $stop; end + foreach (string_index_arr_2[i]) begin + if (string_index_arr_2[i] <= 10) $stop; + end endfunction endclass