diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index a74276358..f37ba9168 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -1218,6 +1218,14 @@ class ConstraintExprVisitor final : public VNVisitor { return preamblep; } + // Create SFormatF for array dereference inside solver + AstSFormatF* createSolverArrDerefp(FileLine* const fl, AstNodeExpr* const arrExprp, + AstNodeExpr* const idxExprp) { + AstNodeExpr* const argsp = AstNode::addNext(arrExprp, idxExprp); + AstSFormatF* const formatp = new AstSFormatF{fl, "(select %s %s)", false, argsp}; + return formatp; + } + // VISITORS void visit(AstNodeVarRef* nodep) override { AstVar* varp = nodep->varp(); @@ -2650,9 +2658,9 @@ class ConstraintExprVisitor final : public VNVisitor { iterateChildren(nodep); AstNodeExpr* const pinp = nodep->pinsp()->unlinkFrBack(); if (VN_IS(pinp, SFormatF) && m_structSel) VN_AS(pinp, SFormatF)->name("%x"); - AstNodeExpr* const argsp = AstNode::addNext(nodep->fromp()->unlinkFrBack(), pinp); AstSFormatF* newp; if (m_structSel) { + AstNodeExpr* const argsp = AstNode::addNext(nodep->fromp()->unlinkFrBack(), pinp); sizep->dtypeSetInt(); AstLogAnd* const condp = new AstLogAnd{ fl, @@ -2663,7 +2671,7 @@ class ConstraintExprVisitor final : public VNVisitor { m_conditionp = m_conditionp ? new AstLogAnd{fl, m_conditionp, condp} : condp; newp = new AstSFormatF{fl, "%s.%s", false, argsp}; } else { - newp = new AstSFormatF{fl, "(select %s %s)", false, argsp}; + newp = createSolverArrDerefp(fl, nodep->fromp()->unlinkFrBack(), pinp); } nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -2874,34 +2882,40 @@ class ConstraintExprVisitor final : public VNVisitor { AstNodeModule* const genModulep = VN_AS(m_genp->user2p(), NodeModule); arrVarp->user3(true); - // Create variable name using AstSFormatF - AstSFormatF* const varNamep = new AstSFormatF{ - fl, smtArrayName + "_%x", false, new AstVarRef{fl, loopVarp, VAccess::READ}}; + // Add write_var call to init task + AstNodeExpr* const arrVarNamep + = new AstCExpr{fl, AstCExpr::Pure{}, "\"" + smtArrayName + "\"", elemWidth}; + AstCMethodHard* const writeVarCallp + = new AstCMethodHard{fl, new AstVarRef{fl, genModulep, m_genp, VAccess::READ}, + VCMethod::RANDOMIZER_WRITE_VAR}; + writeVarCallp->addPinsp(new AstVarRef{fl, arrModulep, arrVarp, VAccess::READ}); + writeVarCallp->addPinsp( + new AstConst{fl, AstConst::Unsized64{}, static_cast(elemWidth)}); + writeVarCallp->addPinsp(arrVarNamep); + const uint32_t unpackedDims = arrVarp->dtypep()->dimensions(false).second; + UASSERT_OBJ(unpackedDims == 1, arrVarp, "Array isn't 1-D"); + writeVarCallp->addPinsp(new AstConst{fl, 1}); // Dimension - // Create array element reference: array.atWrite(index) - AstCMethodHard* const atWritep = new AstCMethodHard{ - fl, new AstVarRef{fl, arrModulep, arrVarp, VAccess::READWRITE}, - VCMethod::ARRAY_AT_WRITE, new AstVarRef{fl, loopVarp, VAccess::READ}}; - atWritep->dtypeFrom(elemDtp); + const RandomizeMode randMode = {.asInt = arrVarp->user1()}; + if (randMode.usesMode) { + writeVarCallp->addPinsp( + new AstConst{fl, AstConst::Unsized64{}, randMode.index}); + } + writeVarCallp->dtypeSetVoid(); + AstNodeFTask* initTaskp = m_inlineInitTaskp; + if (!initTaskp) { + initTaskp = VN_AS(m_memberMap.findMember(arrModulep, "new"), NodeFTask); + UASSERT_OBJ(initTaskp, arrModulep, "No new() in class"); + } + initTaskp->addStmtsp(writeVarCallp->makeStmt()); - // Convert std::string to const char* for write_var - AstCExpr* const varNameCStrp = new AstCExpr{fl, AstCExpr::Pure{}}; - varNameCStrp->dtypeSetString(); - varNameCStrp->add("("); - varNameCStrp->add(varNamep->cloneTree(false)); - varNameCStrp->add(").c_str()"); + // Create solver constraints + AstSFormatF* const idxFormatp = new AstSFormatF{ + fl, "#x%08x", false, new AstVarRef{fl, loopVarp, VAccess::READ}}; + iterateChildren(nodep); + AstSFormatF* const varNamep + = createSolverArrDerefp(fl, nodep->fromp()->unlinkFrBack(), idxFormatp); - // Create write_var method call: gen.write_var(arrElement, width, name, 0) - AstCMethodHard* const writeVarp = new AstCMethodHard{ - fl, new AstVarRef{fl, genModulep, m_genp, VAccess::READWRITE}, - VCMethod::RANDOMIZER_WRITE_VAR, atWritep}; - writeVarp->addPinsp(new AstConst{fl, AstConst::WidthedValue{}, 64, - static_cast(elemWidth)}); - writeVarp->addPinsp(varNameCStrp); - writeVarp->addPinsp(new AstConst{fl, AstConst::WidthedValue{}, 64, 0}); - writeVarp->dtypeSetVoid(); - - cstmtp->add(writeVarp->makeStmt()); cstmtp->add("ret += \" \";\n"); cstmtp->add("ret += "); cstmtp->add(varNamep); diff --git a/test_regress/t/t_constraint_foreach.v b/test_regress/t/t_constraint_foreach.v index 03751acbb..3f5372b34 100644 --- a/test_regress/t/t_constraint_foreach.v +++ b/test_regress/t/t_constraint_foreach.v @@ -153,6 +153,38 @@ class H; } endclass +class I; + rand int a; + rand int arr[]; + constraint c1 { + arr.size() == 5; + foreach(arr[i]) { + arr[i] inside {[10 : 200]}; + } + } + constraint c2 { + a + arr.sum() == 200; + } +endclass + +class J; + rand int a; + rand int arr[]; + + function new(); + arr = new [5]; + endfunction + + constraint c1 { + foreach(arr[i]) { + arr[i] inside {[10 : 200]}; + } + } + constraint c2 { + a + arr.sum() == 200; + } +endclass + module t; initial begin automatic C c = new; @@ -161,6 +193,8 @@ module t; automatic F f = new; automatic G g = new; automatic H h = new; + automatic I i = new; + automatic J j = new; `check_rand(c, c.x, 4 < c.x && c.x < 7); `check_rand(d, d.posit, (d.posit ? 4 : -3) < d.x && d.x < (d.posit ? 7 : 0)); @@ -176,6 +210,14 @@ module t; foreach (h.a[i]) begin `check_rand(h, h.a[i], (h.a[i] != h.b)); end + `check_rand(i, i.a, (i.arr.sum() + i.a == 200)); + foreach (i.arr[it]) begin + `check_rand(i, i.arr[it], (i.arr[it] inside {[10 : 200]})); + end + `check_rand(j, j.a, (j.arr.sum() + j.a == 200)); + foreach (j.arr[i]) begin + `check_rand(j, j.arr[i], (j.arr[i] inside {[10 : 200]})); + end $write("*-* All Finished *-*\n"); $finish; end