mirror of
https://github.com/verilator/verilator.git
synced 2026-09-02 02:38:15 +02:00
This commit is contained in:
+95
-2
@@ -606,6 +606,12 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
// VISITORS
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
AstVar* const varp = nodep->varp();
|
||||
if (varp->user4p()) {
|
||||
varp->user4p()->v3warn(
|
||||
CONSTRAINTIGN,
|
||||
"Size constraint combined with element constraint may not work correctly");
|
||||
}
|
||||
|
||||
AstNodeModule* const classOrPackagep = nodep->classOrPackagep();
|
||||
const RandomizeMode randMode = {.asInt = varp->user1()};
|
||||
if (!randMode.usesMode && editFormat(nodep)) return;
|
||||
@@ -1132,7 +1138,9 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
// AstClass::user2p() -> AstVar*. Rand mode state variable
|
||||
// AstVar::user3() -> bool. Handled in constraints
|
||||
// AstClass::user3p() -> AstVar*. Constrained randomizer variable
|
||||
// AstConstraint::user3p() -> AstTask*. Pointer to resize procedure
|
||||
// AstClass::user4p() -> AstVar*. Constraint mode state variable
|
||||
// AstVar::user4p() -> AstVar*. Size variable for constrained queues
|
||||
// VNUser1InUse m_inuser1; (Allocated for use in RandomizeMarkVisitor)
|
||||
// VNUser2InUse m_inuser2; (Allocated for use in RandomizeMarkVisitor)
|
||||
const VNUser3InUse m_inuser3;
|
||||
@@ -1150,6 +1158,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
size_t m_enumValueTabCount = 0; // Number of tables with enum values created
|
||||
int m_randCaseNum = 0; // Randcase number within a module for var naming
|
||||
std::map<std::string, AstCDType*> m_randcDtypes; // RandC data type deduplication
|
||||
AstConstraint* m_constraintp = nullptr; // Current constraint
|
||||
|
||||
// METHODS
|
||||
void createRandomGenerator(AstClass* const classp) {
|
||||
@@ -1180,6 +1189,17 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
m_memberMap.insert(classp, setupAllTaskp);
|
||||
return setupAllTaskp;
|
||||
}
|
||||
AstTask* getCreateAggrResizeTask(AstClass* const classp) {
|
||||
static const char* const name = "__Vresize_constrained_arrays";
|
||||
AstTask* resizeTaskp = VN_AS(m_memberMap.findMember(classp, name), Task);
|
||||
if (resizeTaskp) return resizeTaskp;
|
||||
resizeTaskp = new AstTask{classp->fileline(), name, nullptr};
|
||||
resizeTaskp->classMethod(true);
|
||||
resizeTaskp->isVirtual(true);
|
||||
classp->addMembersp(resizeTaskp);
|
||||
m_memberMap.insert(classp, resizeTaskp);
|
||||
return resizeTaskp;
|
||||
}
|
||||
AstVar* getCreateRandModeVar(AstClass* const classp) {
|
||||
if (classp->user2p()) return VN_AS(classp->user2p(), Var);
|
||||
if (AstClassExtends* const extendsp = classp->extendsp()) {
|
||||
@@ -1281,8 +1301,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
FileLine* fl = modeVarp->fileline();
|
||||
AstCMethodHard* const dynarrayNewp
|
||||
= new AstCMethodHard{fl, new AstVarRef{fl, modeVarModp, modeVarp, VAccess::WRITE},
|
||||
"renew_copy", new AstConst{fl, modeCount}};
|
||||
dynarrayNewp->addPinsp(new AstVarRef{fl, modeVarModp, modeVarp, VAccess::READ});
|
||||
"resize", new AstConst{fl, modeCount}};
|
||||
dynarrayNewp->dtypeSetVoid();
|
||||
AstNodeFTask* const newp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask);
|
||||
UASSERT_OBJ(newp, classp, "No new() in class");
|
||||
@@ -1565,6 +1584,13 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
nodep->addMembersp(taskp);
|
||||
return taskp;
|
||||
}
|
||||
AstTask* newResizeConstrainedArrayTask(AstClass* const nodep, const std::string& name) {
|
||||
AstTask* const taskp
|
||||
= new AstTask{nodep->fileline(), name + "_resize_constrained_array", nullptr};
|
||||
taskp->classMethod(true);
|
||||
nodep->addMembersp(taskp);
|
||||
return taskp;
|
||||
}
|
||||
AstNodeStmt* implementConstraintsClear(FileLine* const fileline, AstVar* const genp) {
|
||||
AstCMethodHard* const clearp = new AstCMethodHard{
|
||||
fileline,
|
||||
@@ -1898,6 +1924,15 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
|
||||
setupAllTaskp->addStmtsp(setupTaskRefp->makeStmt());
|
||||
|
||||
if (AstTask* const resizeTaskp = VN_CAST(constrp->user3p(), Task)) {
|
||||
AstTask* const resizeAllTaskp = getCreateAggrResizeTask(nodep);
|
||||
AstTaskRef* const resizeTaskRefp
|
||||
= new AstTaskRef{constrp->fileline(), resizeTaskp->name(), nullptr};
|
||||
resizeTaskRefp->taskp(resizeTaskp);
|
||||
resizeTaskRefp->classOrPackagep(classp);
|
||||
resizeAllTaskp->addStmtsp(resizeTaskRefp->makeStmt());
|
||||
}
|
||||
|
||||
ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp, randModeVarp};
|
||||
if (constrp->itemsp()) {
|
||||
taskp->addStmtsp(wrapIfConstraintMode(
|
||||
@@ -1933,6 +1968,13 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
AstVarRef* const fvarRefp = new AstVarRef{fl, fvarp, VAccess::WRITE};
|
||||
randomizep->addStmtsp(new AstAssign{fl, fvarRefp, beginValp});
|
||||
|
||||
if (AstTask* const resizeAllTaskp
|
||||
= VN_AS(m_memberMap.findMember(nodep, "__Vresize_constrained_arrays"), Task)) {
|
||||
AstTaskRef* const resizeTaskRefp = new AstTaskRef{fl, resizeAllTaskp->name(), nullptr};
|
||||
resizeTaskRefp->taskp(resizeAllTaskp);
|
||||
randomizep->addStmtsp(resizeTaskRefp->makeStmt());
|
||||
}
|
||||
|
||||
AstFunc* const basicRandomizep
|
||||
= V3Randomize::newRandomizeFunc(m_memberMap, nodep, "__Vbasic_randomize");
|
||||
addBasicRandomizeBody(basicRandomizep, nodep, randModeVarp);
|
||||
@@ -2161,6 +2203,57 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
UINFO(9, "Added `%s` randomization procedure");
|
||||
VL_DO_DANGLING(withp->deleteTree(), withp);
|
||||
}
|
||||
void visit(AstConstraint* nodep) override {
|
||||
VL_RESTORER(m_constraintp);
|
||||
m_constraintp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstCMethodHard* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
if (m_constraintp && nodep->fromp()->user1() && nodep->name() == "size") {
|
||||
AstClass* const classp = VN_AS(m_modp, Class);
|
||||
AstVarRef* const queueVarRefp = VN_CAST(nodep->fromp(), VarRef);
|
||||
if (!queueVarRefp) {
|
||||
// Warning from ConstraintExprVisitor will be thrown
|
||||
return;
|
||||
}
|
||||
AstVar* const queueVarp = queueVarRefp->varp();
|
||||
AstVar* sizeVarp = VN_CAST(queueVarp->user4p(), Var);
|
||||
if (!sizeVarp) {
|
||||
sizeVarp = new AstVar{fl, VVarType::BLOCKTEMP, "__V" + queueVarp->name() + "_size",
|
||||
nodep->findSigned32DType()};
|
||||
classp->addMembersp(sizeVarp);
|
||||
m_memberMap.insert(classp, sizeVarp);
|
||||
sizeVarp->user2p(classp);
|
||||
|
||||
queueVarp->user4p(sizeVarp);
|
||||
|
||||
AstTask* resizerTaskp = VN_AS(m_constraintp->user3p(), Task);
|
||||
if (!resizerTaskp) {
|
||||
resizerTaskp = newResizeConstrainedArrayTask(classp, m_constraintp->name());
|
||||
m_constraintp->user3p(resizerTaskp);
|
||||
}
|
||||
AstCMethodHard* const resizep
|
||||
= new AstCMethodHard{fl, nodep->fromp()->unlinkFrBack(), "resize",
|
||||
new AstVarRef{fl, sizeVarp, VAccess::READ}};
|
||||
resizep->dtypep(nodep->findVoidDType());
|
||||
resizerTaskp->addStmtsp(new AstStmtExpr{fl, resizep});
|
||||
|
||||
// Since size variable is signed int, we need additional constraint
|
||||
// to make sure it is always >= 0.
|
||||
AstVarRef* const sizeVarRefp = new AstVarRef{fl, sizeVarp, VAccess::READ};
|
||||
sizeVarRefp->user1(true);
|
||||
AstGteS* const sizeGtep = new AstGteS{fl, sizeVarRefp, new AstConst{fl, 0}};
|
||||
sizeGtep->user1(true);
|
||||
m_constraintp->addItemsp(new AstConstraintExpr{fl, sizeGtep});
|
||||
}
|
||||
AstVarRef* const sizeVarRefp = new AstVarRef{fl, sizeVarp, VAccess::READ};
|
||||
sizeVarRefp->user1(true);
|
||||
nodep->replaceWith(sizeVarRefp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstNodeStmt* nodep) override {
|
||||
VL_RESTORER(m_stmtp);
|
||||
m_stmtp = nodep;
|
||||
|
||||
Reference in New Issue
Block a user