diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index cf45eaf21..2c6b8f86b 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -620,6 +620,7 @@ class AstCMethodHard final : public AstNodeExpr { // @astgen op2 := pinsp : List[AstNodeExpr] // Arguments string m_name; // Name of method bool m_pure = false; // Pure optimizable + bool m_usePtr = false; // Use '->' not '.' public: AstCMethodHard(FileLine* fl, AstNodeExpr* fromp, const string& name, AstNodeExpr* pinsp = nullptr) @@ -641,6 +642,8 @@ public: string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } + bool usePtr() const { return m_usePtr; } + void usePtr(bool flag) { m_usePtr = flag; } private: void setPurity(); diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index f8d1e84b4..c458dca2f 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -3116,7 +3116,9 @@ int AstCMethodHard::instrCount() const { return 0; } void AstCMethodHard::setPurity() { - static const std::map isPureMethod{{"andNot", false}, + static const std::map isPureMethod{{"__Vm_rng.get_randstate", true}, + {"__Vm_rng.set_randstate", false}, + {"andNot", false}, {"any", true}, {"anyTriggered", false}, {"assign", false}, @@ -3124,6 +3126,7 @@ void AstCMethodHard::setPurity() { {"atBack", true}, {"atWrite", true}, {"awaitingCurrentTime", true}, + {"basicStdRandomization", false}, {"clear", false}, {"clearFired", false}, {"commit", false}, @@ -3187,8 +3190,7 @@ void AstCMethodHard::setPurity() { {"unique", true}, {"unique_index", true}, {"word", true}, - {"write_var", false}, - {"basicStdRandomization", false}}; + {"write_var", false}}; if (name() == "atWriteAppend" || name() == "atWriteAppendBack") { m_pure = false; diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index bbaf16aad..9b34eae52 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -649,7 +649,7 @@ public: } void visit(AstCMethodHard* nodep) override { iterateConst(nodep->fromp()); - putns(nodep, "."); + putns(nodep, nodep->usePtr() ? "->" : "."); putns(nodep, nodep->name()); puts("("); bool comma = false; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a30d8cb4c..4954a3eff 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4286,11 +4286,31 @@ class WidthVisitor final : public VNVisitor { processFTaskRefArgs(nodep); } return; - } else if (nodep->name() == "get_randstate" || nodep->name() == "set_randstate") { - // See implementations under AstNodeFTaskRef - nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'get_randstate'/'set_randstate' called " - "on object. Suggest call from inside class."); - nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitTrue{}}); + } else if (nodep->name() == "get_randstate") { + methodOkArguments(nodep, 0, 0); + first_classp->baseMostClassp()->needRNG(true); + v3Global.useRandomizeMethods(true); + AstCMethodHard* const newp + = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), + "__Vm_rng.get_randstate", nullptr}; + newp->usePtr(true); + newp->dtypeSetString(); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } else if (nodep->name() == "set_randstate") { + methodOkArguments(nodep, 1, 1); + AstNodeExpr* const expr1p = VN_AS(nodep->pinsp(), Arg)->exprp(); // May edit + iterateCheckString(nodep, "LHS", expr1p, BOTH); + AstNodeExpr* const exprp = VN_AS(nodep->pinsp(), Arg)->exprp(); + first_classp->baseMostClassp()->needRNG(true); + v3Global.useRandomizeMethods(true); + AstCMethodHard* const newp + = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), + "__Vm_rng.set_randstate", exprp->unlinkFrBack()}; + newp->usePtr(true); + newp->dtypeSetString(); + nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); return; } else if (nodep->name() == "constraint_mode") { diff --git a/test_regress/t/t_randstate_obj.out b/test_regress/t/t_randstate_obj.out deleted file mode 100644 index 62595c9e5..000000000 --- a/test_regress/t/t_randstate_obj.out +++ /dev/null @@ -1,10 +0,0 @@ -%Error-UNSUPPORTED: t/t_randstate_obj.v:20:13: Unsupported: 'get_randstate'/'set_randstate' called on object. Suggest call from inside class. - : ... note: In instance 't' - 20 | s = c.get_randstate(); - | ^~~~~~~~~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_randstate_obj.v:26:9: Unsupported: 'get_randstate'/'set_randstate' called on object. Suggest call from inside class. - : ... note: In instance 't' - 26 | c.set_randstate(s); - | ^~~~~~~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_randstate_obj.py b/test_regress/t/t_randstate_obj.py index 710a094ab..d4f986441 100755 --- a/test_regress/t/t_randstate_obj.py +++ b/test_regress/t/t_randstate_obj.py @@ -11,6 +11,8 @@ import vltest_bootstrap test.scenarios('simulator') -test.compile(fails=test.vlt_all, expect_filename=test.golden_filename) +test.compile() + +test.execute() test.passes()