Add support for `this.randomize with` (#5282)

Signed-off-by: Arkadiusz Kozdra <akozdra@antmicro.com>
This commit is contained in:
Arkadiusz Kozdra 2024-07-19 09:14:56 +02:00 committed by GitHub
parent b18037b7e7
commit 43377ed8b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 50 additions and 18 deletions

View File

@ -898,25 +898,33 @@ class RandomizeVisitor final : public VNVisitor {
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstMethodCall* nodep) override {
void visit(AstNodeFTaskRef* nodep) override {
AstWith* const withp = VN_CAST(nodep->pinsp(), With);
if (!(nodep->name() == "randomize") || !withp) {
iterateChildren(nodep);
return;
}
withp->unlinkFrBack();
iterateChildren(nodep);
UASSERT_OBJ(nodep->fromp()->dtypep(), nodep->fromp(), "Object dtype is not linked");
AstClassRefDType* const classrefdtypep = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType);
if (!classrefdtypep) {
nodep->v3warn(E_UNSUPPORTED,
"Inline constraints are not supported for this node type");
return;
AstClass* classp = nullptr;
if (AstMethodCall* const callp = VN_CAST(nodep, MethodCall)) {
UASSERT_OBJ(callp->fromp()->dtypep(), callp->fromp(), "Object dtype is not linked");
AstClassRefDType* const classrefdtypep
= VN_CAST(callp->fromp()->dtypep(), ClassRefDType);
if (!classrefdtypep) {
nodep->v3warn(E_UNSUPPORTED,
"Inline constraints are not supported for this node type");
return;
}
classp = classrefdtypep->classp();
UASSERT_OBJ(classp, classrefdtypep, "Class type is unlinked to its ref type");
} else {
classp = VN_CAST(m_modp, Class);
UASSERT_OBJ(classp, m_modp, "Module not class, should have failed in V3Width");
}
AstClass* const classp = classrefdtypep->classp();
UASSERT_OBJ(classp, classrefdtypep, "Class type is unlinked to its ref type");
if (classp->user1()) {
// We need to first ensure that the class randomizer is instantiated if needed
// NOTE: This is safe only because AstClass visit function overwrites all
@ -985,15 +993,13 @@ class RandomizeVisitor final : public VNVisitor {
solverCallp});
// Replace the node with a call to that function
AstMethodCall* const callp
= new AstMethodCall(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
randomizeFuncp->name(), captured.getArgs());
callp->taskp(randomizeFuncp);
callp->dtypeFrom(randomizeFuncp->dtypep());
callp->classOrPackagep(classp);
nodep->replaceWith(callp);
nodep->name(randomizeFuncp->name());
nodep->addPinsp(captured.getArgs());
nodep->taskp(randomizeFuncp);
nodep->dtypeFrom(randomizeFuncp->dtypep());
nodep->classOrPackagep(classp);
UINFO(9, "Added `%s` randomization procedure");
VL_DO_DANGLING(nodep->deleteTree(), nodep);
VL_DO_DANGLING(withp->deleteTree(), withp);
}
void visit(AstNode* nodep) override { iterateChildren(nodep); }

View File

@ -3132,7 +3132,7 @@ class WidthVisitor final : public VNVisitor {
<< nodep->fromp()->dtypep()->prettyTypeName() << "'");
}
}
AstWith* methodWithArgument(AstMethodCall* nodep, bool required, bool arbReturn,
AstWith* methodWithArgument(AstNodeFTaskRef* nodep, bool required, bool arbReturn,
AstNodeDType* returnDtp, AstNodeDType* indexDtp,
AstNodeDType* valueDtp) {
UASSERT_OBJ(arbReturn || returnDtp, nodep, "Null return type");
@ -5990,6 +5990,7 @@ class WidthVisitor final : public VNVisitor {
// For arguments, is assignment-like context; see IEEE rules in AstNodeAssign
// Function hasn't been widthed, so make it so.
UINFO(5, " FTASKREF " << nodep << endl);
AstWith* withp = nullptr;
if (nodep->name() == "randomize" || nodep->name() == "srandom"
|| (!nodep->taskp()
&& (nodep->name() == "get_randstate" || nodep->name() == "set_randstate"))) {
@ -5998,6 +5999,15 @@ class WidthVisitor final : public VNVisitor {
UASSERT_OBJ(classp, nodep, "Should have failed in V3LinkDot");
if (nodep->name() == "randomize") {
nodep->taskp(V3Randomize::newRandomizeFunc(m_memberMap, classp));
AstClassRefDType* const adtypep
= new AstClassRefDType{nodep->fileline(), classp, nullptr};
v3Global.rootp()->typeTablep()->addTypesp(adtypep);
withp = methodWithArgument(nodep, false, false, adtypep->findVoidDType(),
adtypep->findBitDType(), adtypep);
if (nodep->pinsp()) {
nodep->pinsp()->v3warn(CONSTRAINTIGN, "rand_mode ignored (unsupported)");
nodep->pinsp()->unlinkFrBackWithNext()->deleteTree();
}
} else if (nodep->name() == "srandom") {
nodep->taskp(V3Randomize::newSRandomFunc(m_memberMap, classp));
m_memberMap.clear();
@ -6041,6 +6051,7 @@ class WidthVisitor final : public VNVisitor {
userIterate(nodep->taskp(), nullptr);
// And do the arguments to the task/function too
processFTaskRefArgs(nodep);
nodep->addPinsp(withp);
nodep->didWidth(true);
}
void visit(AstNodeProcedure* nodep) override {

View File

@ -30,6 +30,9 @@ class Foo extends Boo;
endfunction
constraint constr1_c { b < x; }
function bit test_this_randomize;
return this.randomize() with { a <= boo; } == 1;
endfunction
endclass
// Current AstWith representation makes VARs of caller indistinguishable from VARs of randomized
@ -55,6 +58,13 @@ class Baz;
rand int v;
endclass
class Baz2;
rand int v;
function bit test_this_randomize;
return this.randomize() with { v == 5; } == 1;
endfunction
endclass
module submodule();
int sub_var = 7;
endmodule
@ -75,6 +85,7 @@ module mwith();
int c = 30;
Foo foo = new(c);
Baz baz = new;
Baz2 baz2 = new;
Bar bar = new;
$display("foo.x = %d", foo.x);
$display("-----------------");
@ -105,6 +116,10 @@ module mwith();
if (!bar.test_capture_of_callers_derived_var(foo)) $stop;
// Check randomization with non-captured non-static variable from different AstNodeModule
if (!Bar::test_capture_of_callees_derived_var(foo)) $stop;
// Check this.randomize()
if (!foo.test_this_randomize()) $stop;
// Check this.randomize() with no constraints
if (!baz2.test_this_randomize()) $stop;
$write("*-* All Finished *-*\n");
$finish();