diff --git a/include/verilated_random.h b/include/verilated_random.h index aae19ddf1..f75b199d5 100644 --- a/include/verilated_random.h +++ b/include/verilated_random.h @@ -382,8 +382,9 @@ public: // Register associative array of non-struct types template - void write_var(VlAssocArray& var, int width, const char* name, int dimension, - std::uint32_t randmodeIdx = std::numeric_limits::max()) { + typename std::enable_if::value, void>::type + write_var(VlAssocArray& var, int width, const char* name, int dimension, + std::uint32_t randmodeIdx = std::numeric_limits::max()) { if (m_vars.find(name) != m_vars.end()) return; m_vars[name] = std::make_shared>>( @@ -394,8 +395,13 @@ public: } } - // TODO: Register associative array of structs - + // Register associative array of structs + template + typename std::enable_if::value, void>::type + write_var(VlAssocArray& var, int width, const char* name, int dimension, + std::uint32_t randmodeIdx = std::numeric_limits::max()) { + if (dimension > 0) record_struct_arr(var, name, dimension, {}, {}); + } // ---------------------------------------- // --- Record Arrays: flat and struct --- // ---------------------------------------- @@ -476,10 +482,12 @@ public: std::vector idxWidths) { std::ostringstream oss; for (size_t i = 0; i < indices.size(); ++i) { - oss << std::hex << static_cast(indices[i]); + oss << std::hex << std::setw(int(idxWidths[i] / 4)) << std::setfill('0') + << static_cast(indices[i]); if (i < indices.size() - 1) oss << "."; } - write_var(var, 1ULL, (name + "." + oss.str()).c_str(), 1ULL); + write_var(var, 1ULL, + oss.str().length() > 0 ? (name + "." + oss.str()).c_str() : name.c_str(), 1ULL); } // Recursively process VlUnpacked of structs @@ -487,7 +495,8 @@ public: void record_struct_arr(VlUnpacked& var, const std::string name, int dimension, std::vector indices, std::vector idxWidths) { if (dimension > 0 && N_Depth != 0) { - idxWidths.push_back(32); + constexpr size_t idx_width = 1 << VL_CLOG2_CE_Q(VL_CLOG2_CE_Q(N_Depth) + 1); + idxWidths.push_back(idx_width); for (size_t i = 0; i < N_Depth; ++i) { indices.push_back(i); record_struct_arr(var.operator[](i), name, dimension - 1, indices, idxWidths); @@ -510,9 +519,32 @@ public: } } - // TODO: Add support for associative arrays of structs // Recursively process associative arrays of structs + template + void record_struct_arr(VlAssocArray& var, const std::string name, + int dimension, std::vector indices, + std::vector idxWidths) { + if ((dimension > 0) && (!var.empty())) { + for (auto it = var.begin(); it != var.end(); ++it) { + const T_Key& key = it->first; + const T_Value& value = it->second; + std::string indexed_name; + std::vector integral_index; + size_t idx_width = 0; + + process_key(key, indexed_name, integral_index, name, idx_width); + std::ostringstream oss; + for (int i = 0; i < integral_index.size(); ++i) + oss << std::hex << static_cast(integral_index[i]); + + std::string result = oss.str(); + result.insert(result.begin(), int(idx_width / 4) - result.size(), '0'); + record_struct_arr(var.at(key), name + "." + result, dimension - 1, indices, + idxWidths); + } + } + } // -------------------------- // --- Helper functions --- // -------------------------- diff --git a/include/verilated_types.h b/include/verilated_types.h index 783ba5a65..70e131423 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -969,6 +969,7 @@ public: // Size of array. Verilog: function int size(), or int num() int size() const { return m_map.size(); } + bool empty() const { return m_map.empty(); } // Clear array. Verilog: function void delete([input index]) void clear() { m_map.clear(); } void erase(const T_Key& index) { m_map.erase(index); } @@ -1265,7 +1266,7 @@ std::string VL_TO_STRING(const VlAssocArray& obj) { } template -struct VlContainsCustomStruct> : VlContainsCustomStruct {}; +struct VlContainsCustomStruct> : VlContainsCustomStruct {}; template void VL_READMEM_N(bool hex, int bits, const std::string& filename, @@ -1597,8 +1598,8 @@ std::string VL_TO_STRING(const VlUnpacked& obj) { return obj.to_string(); } -template -struct VlContainsCustomStruct> : VlContainsCustomStruct {}; +template +struct VlContainsCustomStruct> : VlContainsCustomStruct {}; //=================================================================== // Helper to apply the given indices to a target expression diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index ff7353eb9..c1e5c756d 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -541,7 +541,7 @@ class ConstraintExprVisitor final : public VNVisitor { AstSFormatF* const newp = new AstSFormatF{nodep->fileline(), smtExpr, false, argsp}; if (m_structSel && newp->name() == "(select %@ %@)") { newp->name("%@.%@"); - newp->exprsp()->nextp()->name("%x"); + if (!VN_IS(nodep, AssocSel)) newp->exprsp()->nextp()->name("%x"); } nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -734,8 +734,10 @@ class ConstraintExprVisitor final : public VNVisitor { } } // Mark Random for structArray - if (VN_IS(nodep->fromp(), ArraySel)) { - AstNodeExpr* const fromp = VN_AS(nodep->fromp(), ArraySel)->fromp(); + if (VN_IS(nodep->fromp(), ArraySel) || VN_IS(nodep->fromp(), CMethodHard)) { + AstNodeExpr* const fromp = VN_IS(nodep->fromp(), ArraySel) + ? VN_AS(nodep->fromp(), ArraySel)->fromp() + : VN_AS(nodep->fromp(), CMethodHard)->fromp(); AstStructDType* const dtypep = VN_AS(fromp->dtypep()->skipRefp()->subDTypep()->skipRefp(), StructDType); dtypep->markConstrainedRand(true); @@ -755,7 +757,8 @@ class ConstraintExprVisitor final : public VNVisitor { if (VN_AS(nodep->fromp(), SFormatF)->name() == "%@.%@") { newp = new AstSFormatF{fl, "%@.%@." + nodep->name(), false, VN_AS(nodep->fromp(), SFormatF)->exprsp()->cloneTreePure(true)}; - newp->exprsp()->nextp()->name("%x"); + if (newp->exprsp()->nextp()->name().rfind("#x", 0) == 0) + newp->exprsp()->nextp()->name("%x"); // for #x%x to %x } else { newp = new AstSFormatF{fl, nodep->fromp()->name() + "." + nodep->name(), false, nullptr}; @@ -767,10 +770,11 @@ class ConstraintExprVisitor final : public VNVisitor { void visit(AstAssocSel* nodep) override { if (editFormat(nodep)) return; FileLine* const fl = nodep->fileline(); + // Adaptive formatting and type handling for associative array keys 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)}; + AstNodeExpr* const idxp = new AstSFormatF{fl, (m_structSel ? "%32p" : "#x%32p"), false, + nodep->bitp()->unlinkFrBack(&handle)}; handle.relink(idxp); editSMT(nodep, nodep->fromp(), idxp); } else if (VN_IS(nodep->bitp(), CvtPackString) @@ -784,8 +788,8 @@ class ConstraintExprVisitor final : public VNVisitor { << stringSize << "bits, limit is 128 bits"); } VNRelinker handle; - AstNodeExpr* const idxp - = new AstSFormatF{fl, "#x%32x", false, stringp->lhsp()->unlinkFrBack(&handle)}; + AstNodeExpr* const idxp = new AstSFormatF{fl, (m_structSel ? "%32x" : "#x%32x"), false, + stringp->lhsp()->unlinkFrBack(&handle)}; handle.relink(idxp); editSMT(nodep, nodep->fromp(), idxp); } else { @@ -799,13 +803,13 @@ class ConstraintExprVisitor final : public VNVisitor { std::string fmt; // Normalize to standard bit width if (actual_width <= 8) { - fmt = "#x%2x"; + fmt = m_structSel ? "%2x" : "#x%2x"; } else if (actual_width <= 16) { - fmt = "#x%4x"; + fmt = m_structSel ? "%4x" : "#x%4x"; } else { - fmt = "#x%" + std::to_string(VL_WORDS_I(actual_width) * 8) + "x"; + fmt = (m_structSel ? "%" : "#x%") + + std::to_string(VL_WORDS_I(actual_width) * 8) + "x"; } - AstNodeExpr* const idxp = new AstSFormatF{fl, fmt, false, nodep->bitp()->unlinkFrBack(&handle)}; handle.relink(idxp); diff --git a/test_regress/t/t_constraint_struct_complex.v b/test_regress/t/t_constraint_struct_complex.v index 30626219c..6ad6ba90e 100755 --- a/test_regress/t/t_constraint_struct_complex.v +++ b/test_regress/t/t_constraint_struct_complex.v @@ -4,8 +4,10 @@ // any use, without warranty, 2025 by PlanV GmbH. // SPDX-License-Identifier: CC0-1.0 + class ArrayStruct; /* verilator lint_off SIDEEFFECT */ + // Struct with an unpacked array typedef int arr_3_t[3]; typedef int arr_4_t[4]; @@ -51,19 +53,25 @@ class ArrayStruct; foreach (s1.arr[i]) s1.arr[i] inside {1, 2, 3, 4}; foreach (s1.arr_3[i]) s1.arr_3[i] inside {11, 22, 33, 44, 55}; } + constraint c_dynamic { foreach (s2.arr[i]) s2.arr[i] inside {[10:20]}; } + constraint c_queue { foreach (s3.arr[i]) s3.arr[i] inside {[100:200]}; } + constraint c_assoc { s4.arr["one"] inside {[10:50]}; s4.arr["two"] inside {[51:100]}; s4.arr["three"] inside {[101:150]}; } + constraint c_multi_dim { foreach (s5.arr[i, j]) s5.arr[i][j] inside {[0:9]}; } + constraint c_mix { foreach (s6.mix_arr[i, j]) s6.mix_arr[i][j] inside {[50:100]}; } function new(); + s1.arr = '{1, 2, 3}; s1.arr_3 = '{1, 2, 3}; s1.arr_4 = '{0, 2, 3, 4}; @@ -81,9 +89,11 @@ class ArrayStruct; foreach (s6.mix_arr[i]) begin s6.mix_arr[i] = new[i + 1]; end + endfunction function void print(); + foreach (s1.arr[i]) $display("s1.arr[%0d] = %0d", i, s1.arr[i]); foreach (s1.arr_3[i]) $display("s1.arr_3[%0d] = %0d", i, s1.arr_3[i]); foreach (s1.arr_4[i]) $display("s1.arr_4[%0d] = %0d", i, s1.arr_4[i]); @@ -92,10 +102,12 @@ class ArrayStruct; foreach (s4.arr[i]) $display("s4.arr[\"%s\"] = %0d", i, s4.arr[i]); foreach (s5.arr[i, j]) $display("s5.arr[%0d][%0d] = %0d", i, j, s5.arr[i][j]); foreach (s6.mix_arr[i, j]) $display("s6.mix_arr[%0d][%0d] = %0d", i, j, s6.mix_arr[i][j]); + endfunction // Self-test function to verify constraints function void self_test(); + foreach (s1.arr[i]) if (!(s1.arr[i] inside {1, 2, 3, 4})) $stop; foreach (s1.arr_3[i]) if (!(s1.arr_3[i] inside {11, 22, 33, 44, 55})) $stop; // Note: s1.arr_4[0] is not rand @@ -108,6 +120,7 @@ class ArrayStruct; foreach (s5.arr[i, j]) if (!(s5.arr[i][j] inside {[0:9]})) $stop; foreach (s6.mix_arr[i]) if (s6.mix_arr[i].size() == 0) $stop; foreach (s6.mix_arr[i, j]) if (!(s6.mix_arr[i][j] inside {[50:100]})) $stop; + endfunction /* verilator lint_off SIDEEFFECT */ endclass @@ -115,66 +128,363 @@ endclass class StructArray; /* verilator lint_off WIDTHTRUNC */ typedef struct { - rand int arr[3]; + rand int arr[3]; // static unpacked array rand int a; rand bit [3:0] b; bit c; } struct_t; - rand struct_t s_arr[2]; - constraint c_structArray_0 { + rand struct_t s_arr[2]; + rand struct_t s_2d_arr[2][3]; + rand struct_t s_dyn_arr[]; + rand struct_t s_que_arr[$]; + rand struct_t s_assoc_arr[string]; + rand struct_t s_assoc_arr_2[bit[5:0]]; + + constraint c_arr { foreach (s_arr[i]) foreach (s_arr[i].arr[j]) s_arr[i].arr[j] inside {[0:9]}; + foreach (s_2d_arr[i, j]) + foreach (s_2d_arr[i][j].arr[k]) + s_2d_arr[i][j].arr[k] inside {[9:19]}; + foreach (s_dyn_arr[i]) + foreach (s_dyn_arr[i].arr[j]) + s_dyn_arr[i].arr[j] inside {[19:29]}; + foreach (s_que_arr[i]) + foreach (s_que_arr[i].arr[j]) + s_que_arr[i].arr[j] inside {[29:39]}; + foreach (s_assoc_arr[i]) + foreach (s_assoc_arr[i].arr[j]) + s_assoc_arr[i].arr[j] inside {[39:49]}; + foreach (s_assoc_arr_2[i]) + foreach (s_assoc_arr_2[i].arr[j]) + s_assoc_arr_2[i].arr[j] inside {[49:59]}; } - constraint c_structArray_1 { - foreach (s_arr[i]) s_arr[i].a inside {[10:20]}; + + constraint c_others { + foreach (s_arr[i]) s_arr[i].a inside {[40:50]}; + foreach (s_arr[i]) s_arr[i].b inside {[0:7]}; + + foreach (s_2d_arr[i, j]) s_2d_arr[i][j].a inside {[50:60]}; + + foreach (s_dyn_arr[i]) s_dyn_arr[i].a inside {[60:70]}; + + foreach (s_que_arr[i]) s_que_arr[i].a inside {[70:80]}; + + foreach (s_assoc_arr[i]) s_assoc_arr[i].a inside {[80:90]}; + + foreach (s_assoc_arr_2[i]) s_assoc_arr_2[i].a inside {[90:100]}; } function new(); + foreach (s_arr[i]) begin - foreach (s_arr[i].arr[j]) s_arr[i].arr[j] = 'h0 + j; - s_arr[i].a = 'h10 + i; - s_arr[i].b = 'h0 + i; - s_arr[i].c = i; + foreach (s_arr[i].arr[j]) + s_arr[i].arr[j] = j; + s_arr[i].a = 40 + i; + s_arr[i].b = i; + s_arr[i].c = 0; end + + foreach (s_2d_arr[i, j]) begin + foreach (s_2d_arr[i][j].arr[k]) + s_2d_arr[i][j].arr[k] = k + 10; + s_2d_arr[i][j].a = 50 + i + j; + s_2d_arr[i][j].b = i + j; + s_2d_arr[i][j].c = 0; + end + + foreach (s_dyn_arr[i]) begin + s_dyn_arr = new[3]; + foreach (s_dyn_arr[i].arr[j]) + s_dyn_arr[i].arr[j] = j + 20; + s_dyn_arr[i].a = 60 + i; + s_dyn_arr[i].b = i; + s_dyn_arr[i].c = 0; + end + + for (int i = 0; i < 3; i++) begin + s_que_arr.push_back('{arr: '{30, 31, 32}, a: 70 + i, b: i, c: 0}); + end + + // Associative array with string index + foreach (s_assoc_arr["x"].arr[j]) + s_assoc_arr["x"].arr[j] = j + 40; + foreach (s_assoc_arr["y"].arr[j]) + s_assoc_arr["y"].arr[j] = j + 50; + foreach (s_assoc_arr["long_string_index"].arr[j]) + s_assoc_arr["long_string_index"].arr[j] = j + 60; + s_assoc_arr["x"].a = 80; + s_assoc_arr["x"].b = 0; + s_assoc_arr["x"].c = 0; + s_assoc_arr["y"].a = 90; + s_assoc_arr["y"].b = 1; + s_assoc_arr["y"].c = 0; + s_assoc_arr["long_string_index"].a = 100; + s_assoc_arr["long_string_index"].b = 2; + s_assoc_arr["long_string_index"].c = 0; + + foreach (s_assoc_arr_2[6'd30].arr[j]) + s_assoc_arr_2[6'd30].arr[j] = j + 70; + foreach (s_assoc_arr_2[6'd7].arr[j]) + s_assoc_arr_2[6'd7].arr[j] = j + 80; + s_assoc_arr_2[6'd30].a = 90; + s_assoc_arr_2[6'd30].b = 0; + s_assoc_arr_2[6'd30].c = 0; + s_assoc_arr_2[6'd7].a = 100; + s_assoc_arr_2[6'd7].b = 1; + s_assoc_arr_2[6'd7].c = 0; + endfunction function void print(); + foreach (s_arr[i]) begin - foreach (s_arr[i].arr[j]) $display("s_arr[%0d].arr[%0d] = %0d", i, j, s_arr[i].arr[j]); + foreach (s_arr[i].arr[j]) + $display("s_arr[%0d].arr[%0d] = %0d", i, j, s_arr[i].arr[j]); $display("s_arr[%0d].a = %0d", i, s_arr[i].a); $display("s_arr[%0d].b = %0d", i, s_arr[i].b); $display("s_arr[%0d].c = %0d", i, s_arr[i].c); end + + foreach (s_2d_arr[i, j]) begin + foreach (s_2d_arr[i][j].arr[k]) + $display("s_2d_arr[%0d][%0d].arr[%0d] = %0d", i, j, k, s_2d_arr[i][j].arr[k]); + $display("s_2d_arr[%0d][%0d].a = %0d", i, j, s_2d_arr[i][j].a); + $display("s_2d_arr[%0d][%0d].b = %0d", i, j, s_2d_arr[i][j].b); + $display("s_2d_arr[%0d][%0d].c = %0d", i, j, s_2d_arr[i][j].c); + end + + foreach (s_dyn_arr[i]) begin + foreach (s_dyn_arr[i].arr[j]) + $display("s_dyn_arr[%0d].arr[%0d] = %0d", i, j, s_dyn_arr[i].arr[j]); + $display("s_dyn_arr[%0d].a = %0d", i, s_dyn_arr[i].a); + $display("s_dyn_arr[%0d].b = %0d", i, s_dyn_arr[i].b); + $display("s_dyn_arr[%0d].c = %0d", i, s_dyn_arr[i].c); + end + + foreach (s_que_arr[i]) begin + foreach (s_que_arr[i].arr[j]) + $display("s_que_arr[%0d].arr[%0d] = %0d", i, j, s_que_arr[i].arr[j]); + $display("s_que_arr[%0d].a = %0d", i, s_que_arr[i].a); + $display("s_que_arr[%0d].b = %0d", i, s_que_arr[i].b); + $display("s_que_arr[%0d].c = %0d", i, s_que_arr[i].c); + end + + foreach (s_assoc_arr["x"].arr[j]) + $display("s_assoc_arr[x].arr[%0d] = %0d", j, s_assoc_arr["x"].arr[j]); + $display("s_assoc_arr[x].a = %0d", s_assoc_arr["x"].a); + $display("s_assoc_arr[x].b = %0d", s_assoc_arr["x"].b); + $display("s_assoc_arr[x].c = %0d", s_assoc_arr["x"].c); + foreach (s_assoc_arr["y"].arr[j]) + $display("s_assoc_arr[y].arr[%0d] = %0d", j, s_assoc_arr["y"].arr[j]); + $display("s_assoc_arr[y].a = %0d", s_assoc_arr["y"].a); + $display("s_assoc_arr[y].b = %0d", s_assoc_arr["y"].b); + $display("s_assoc_arr[y].c = %0d", s_assoc_arr["y"].c); + foreach (s_assoc_arr["long_string_index"].arr[j]) + $display("s_assoc_arr[long_string_index].arr[%0d] = %0d", j, s_assoc_arr["long_string_index"].arr[j]); + $display("s_assoc_arr[long_string_index].a = %0d", s_assoc_arr["long_string_index"].a); + $display("s_assoc_arr[long_string_index].b = %0d", s_assoc_arr["long_string_index"].b); + $display("s_assoc_arr[long_string_index].c = %0d", s_assoc_arr["long_string_index"].c); + + foreach (s_assoc_arr_2[6'd30].arr[j]) + $display("s_assoc_arr_2[30].arr[%0d] = %0d", j, s_assoc_arr_2[6'd30].arr[j]); + $display("s_assoc_arr_2[30].a = %0d", s_assoc_arr_2[6'd30].a); + $display("s_assoc_arr_2[30].b = %0d", s_assoc_arr_2[6'd30].b); + $display("s_assoc_arr_2[30].c = %0d", s_assoc_arr_2[6'd30].c); + foreach (s_assoc_arr_2[6'd7].arr[j]) + $display("s_assoc_arr_2[7].arr[%0d] = %0d", j, s_assoc_arr_2[6'd7].arr[j]); + $display("s_assoc_arr_2[7].a = %0d", s_assoc_arr_2[6'd7].a); + $display("s_assoc_arr_2[7].b = %0d", s_assoc_arr_2[6'd7].b); + $display("s_assoc_arr_2[7].c = %0d", s_assoc_arr_2[6'd7].c); + endfunction function void self_test(); + foreach (s_arr[i]) begin - foreach (s_arr[i].arr[j]) if (!(s_arr[i].arr[j] inside {[0:9]})) $stop; - if (!(s_arr[i].a inside {[10:20]})) $stop; - if (!(s_arr[0].c == 0)) $stop; - if (!(s_arr[1].c == 1)) $stop; + foreach (s_arr[i].arr[j]) + if (!(s_arr[i].arr[j] inside {[0:9]})) $stop; + if (!(s_arr[i].a inside {[40:50]})) $stop; end + + foreach (s_2d_arr[i, j]) begin + foreach (s_2d_arr[i][j].arr[k]) + if (!(s_2d_arr[i][j].arr[k] inside {[9:19]})) $stop; + if (!(s_2d_arr[i][j].a inside {[50:60]})) $stop; + end + + foreach (s_dyn_arr[i]) begin + foreach (s_dyn_arr[i].arr[j]) + if (!(s_dyn_arr[i].arr[j] inside {[19:29]})) $stop; + if (!(s_dyn_arr[i].a inside {[60:70]})) $stop; + end + + foreach (s_que_arr[i]) begin + foreach (s_que_arr[i].arr[j]) + if (!(s_que_arr[i].arr[j] inside {[29:39]})) $stop; + if (!(s_que_arr[i].a inside {[70:80]})) $stop; + end + + foreach (s_assoc_arr["x"].arr[j]) + if (!(s_assoc_arr["x"].arr[j] inside {[39:49]})) $stop; + if (!(s_assoc_arr["x"].a inside {[80:90]})) $stop; + foreach (s_assoc_arr["y"].arr[j]) + if (!(s_assoc_arr["y"].arr[j] inside {[39:49]})) $stop; + if (!(s_assoc_arr["y"].a inside {[80:90]})) $stop; + foreach (s_assoc_arr["long_string_index"].arr[j]) + if (!(s_assoc_arr["long_string_index"].arr[j] inside {[39:49]})) $stop; + if (!(s_assoc_arr["long_string_index"].a inside {[80:90]})) $stop; + + foreach (s_assoc_arr_2[6'd30].arr[j]) + if (!(s_assoc_arr_2[6'd30].arr[j] inside {[49:59]})) $stop; + if (!(s_assoc_arr_2[6'd30].a inside {[90:100]})) $stop; + foreach (s_assoc_arr_2[6'd7].arr[j]) + if (!(s_assoc_arr_2[6'd7].arr[j] inside {[49:59]})) $stop; + if (!(s_assoc_arr_2[6'd7].a inside {[90:100]})) $stop; + endfunction + + /* verilator lint_off WIDTHTRUNC */ +endclass + +class MixedStructure; + /* verilator lint_off WIDTHTRUNC */ + typedef struct { + rand int arr[3]; // static unpacked array + rand int dyn[]; // dynamic array + rand int que[$]; // queue + rand int assoc[string]; // associative array with string key + rand int a; + rand bit [3:0] b; + bit c; + } struct_t; + + rand struct_t s_arr[2]; + + constraint c_static { + foreach (s_arr[i]) + foreach (s_arr[i].arr[j]) + s_arr[i].arr[j] inside {[0:9]}; + } + + constraint c_dyn { + foreach (s_arr[i]) + foreach (s_arr[i].dyn[j]) + s_arr[i].dyn[j] inside {[10:19]}; + } + + constraint c_queue { + foreach (s_arr[i]) + foreach (s_arr[i].que[j]) + s_arr[i].que[j] inside {[20:29]}; + } + + constraint c_assoc { + foreach (s_arr[i]) { + s_arr[i].assoc["x"] inside {[30:39]}; + s_arr[i].assoc["y"] inside {[30:39]}; + } + } + + constraint c_other { + foreach (s_arr[i]) s_arr[i].a inside {[40:50]}; + } + + function new(); + + foreach (s_arr[i]) begin + s_arr[i].dyn = new[2]; + s_arr[i].que = {0, 0}; + s_arr[i].assoc = '{"x": 0, "y": 0}; + + foreach (s_arr[i].arr[j]) + s_arr[i].arr[j] = j; + foreach (s_arr[i].dyn[j]) + s_arr[i].dyn[j] = 10 + j; + foreach (s_arr[i].que[j]) + s_arr[i].que[j] = 20 + j; + + s_arr[i].assoc["x"] = i + 30; + s_arr[i].assoc["y"] = i + 31; + s_arr[i].a = 40 + i; + s_arr[i].b = i; + s_arr[i].c = i; + end + + endfunction + + function void print(); + + foreach (s_arr[i]) begin + foreach (s_arr[i].arr[j]) + $display("s_arr[%0d].arr[%0d] = %0d", i, j, s_arr[i].arr[j]); + foreach (s_arr[i].dyn[j]) + $display("s_arr[%0d].dyn[%0d] = %0d", i, j, s_arr[i].dyn[j]); + foreach (s_arr[i].que[j]) + $display("s_arr[%0d].que[%0d] = %0d", i, j, s_arr[i].que[j]); + + $display("s_arr[%0d].assoc[\"x\"] = %0d", i, s_arr[i].assoc["x"]); + $display("s_arr[%0d].assoc[\"y\"] = %0d", i, s_arr[i].assoc["y"]); + $display("s_arr[%0d].a = %0d", i, s_arr[i].a); + $display("s_arr[%0d].b = %0d", i, s_arr[i].b); + $display("s_arr[%0d].c = %0d", i, s_arr[i].c); + end + + endfunction + + function void self_test(); + + foreach (s_arr[i]) begin + foreach (s_arr[i].arr[j]) + if (!(s_arr[i].arr[j] inside {[0:9]})) $stop; + foreach (s_arr[i].dyn[j]) + if (!(s_arr[i].dyn[j] inside {[10:19]})) $stop; + foreach (s_arr[i].que[j]) + if (!(s_arr[i].que[j] inside {[20:29]})) $stop; + if (!(s_arr[i].assoc.exists("x") && s_arr[i].assoc["x"] inside {[30:39]})) $stop; + if (!(s_arr[i].assoc.exists("y") && s_arr[i].assoc["y"] inside {[30:39]})) $stop; + if (!(s_arr[i].a inside {[40:50]})) $stop; + if (i == 0 && s_arr[i].c != 0) $stop; + if (i == 1 && s_arr[i].c != 1) $stop; + end + + endfunction + /* verilator lint_off WIDTHTRUNC */ endclass module t_constraint_struct_complex; + int success; ArrayStruct as_c; StructArray sa_c; + MixedStructure mixed_c; + initial begin as_c = new(); sa_c = new(); + mixed_c = new(); + success = as_c.randomize(); if (success != 1) $stop; as_c.self_test(); // as_c.print(); + // $display(" ArrayStruct passed! \n"); + success = sa_c.randomize(); if (success != 1) $stop; sa_c.self_test(); // sa_c.print(); + // $display(" StructArray passed! \n"); + + success = mixed_c.randomize(); + if (success != 1) $stop; + mixed_c.self_test(); + // mixed_c.print(); + // $display(" MixedStructure passed! \n"); + $write("*-* All Finished *-*\n"); $finish; end