Add warning on dist in constraints (#5264)
This commit is contained in:
parent
34e37d7bd0
commit
0a9b31bb30
|
|
@ -1142,6 +1142,39 @@ public:
|
|||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
};
|
||||
class AstDist final : public AstNodeExpr {
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
// @astgen op2 := itemsp : List[AstDistItem]
|
||||
public:
|
||||
AstDist(FileLine* fl, AstNodeExpr* exprp, AstDistItem* itemsp)
|
||||
: ASTGEN_SUPER_Inside(fl) {
|
||||
this->exprp(exprp);
|
||||
this->addItemsp(itemsp);
|
||||
dtypeSetBit();
|
||||
}
|
||||
ASTGEN_MEMBERS_AstDist;
|
||||
string emitVerilog() override { return "%l dist { %r }"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return false; } // NA
|
||||
};
|
||||
class AstDistItem final : public AstNodeExpr {
|
||||
// Constraint distribution item
|
||||
// @astgen op1 := rangep : AstNodeExpr
|
||||
// @astgen op2 := weightp : AstNodeExpr
|
||||
bool m_isWhole = false; // True for weight ':/', false for ':='
|
||||
public:
|
||||
AstDistItem(FileLine* fl, AstNodeExpr* rangep, AstNodeExpr* weightp)
|
||||
: ASTGEN_SUPER_DistItem(fl) {
|
||||
this->rangep(rangep);
|
||||
this->weightp(weightp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstDistItem;
|
||||
string emitVerilog() override { return "%l "s + (m_isWhole ? ":/" : ":=") + " %r"; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return false; } // NA
|
||||
void isWhole(bool flag) { m_isWhole = flag; }
|
||||
bool isWhole() const { return m_isWhole; }
|
||||
};
|
||||
class AstDot final : public AstNodeExpr {
|
||||
// A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef
|
||||
// These are eliminated in the link stage
|
||||
|
|
|
|||
|
|
@ -1064,24 +1064,6 @@ public:
|
|||
bool same(const AstNode*) const override { return true; }
|
||||
string path() const { return m_path; }
|
||||
};
|
||||
class AstDistItem final : public AstNode {
|
||||
// Constraint distribution item
|
||||
// @astgen op1 := rangep : AstNodeExpr
|
||||
// @astgen op2 := weightp : AstNodeExpr
|
||||
bool m_isWhole = false; // True for weight ':/', false for ':='
|
||||
public:
|
||||
AstDistItem(FileLine* fl, AstNodeExpr* rangep, AstNodeExpr* weightp)
|
||||
: ASTGEN_SUPER_DistItem(fl) {
|
||||
this->rangep(rangep);
|
||||
this->weightp(weightp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstDistItem;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
void isWhole(bool flag) { m_isWhole = flag; }
|
||||
bool isWhole() const { return m_isWhole; }
|
||||
};
|
||||
class AstDpiExport final : public AstNode {
|
||||
// We could put an AstNodeFTaskRef instead of the verilog function name,
|
||||
// however we're not *calling* it, so that seems somehow wrong.
|
||||
|
|
|
|||
|
|
@ -328,6 +328,11 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
// Fall back to "(ite cond then else)"
|
||||
visit(static_cast<AstNodeTriop*>(nodep));
|
||||
}
|
||||
void visit(AstDist* nodep) override {
|
||||
nodep->v3warn(CONSTRAINTIGN, "Constraint expression ignored (unsupported)");
|
||||
nodep->replaceWith(new AstSFormatF{nodep->fileline(), "true", false, nullptr});
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void visit(AstReplicate* nodep) override {
|
||||
// Biop, but RHS is harmful
|
||||
if (editFormat(nodep)) return;
|
||||
|
|
|
|||
|
|
@ -2150,8 +2150,11 @@ class WidthVisitor final : public VNVisitor {
|
|||
userIterateAndNext(nodep->rangesp(), WidthVP{SELF, BOTH}.p());
|
||||
}
|
||||
void visit(AstDistItem* nodep) override {
|
||||
userIterate(nodep->rangep(), WidthVP{SELF, BOTH}.p());
|
||||
userIterate(nodep->weightp(), WidthVP{SELF, BOTH}.p());
|
||||
userIterate(nodep->rangep(), m_vup);
|
||||
if (m_vup->prelim()) { // First stage evaluation
|
||||
userIterate(nodep->weightp(), WidthVP{SELF, BOTH}.p());
|
||||
}
|
||||
nodep->dtypep(nodep->rangep()->dtypep());
|
||||
}
|
||||
void visit(AstVar* nodep) override {
|
||||
// if (debug()) nodep->dumpTree("- InitPre: ");
|
||||
|
|
@ -2574,6 +2577,46 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
}
|
||||
void visit(AstDist* nodep) override {
|
||||
userIterateAndNext(nodep->exprp(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||
for (AstNode *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
|
||||
nextip = itemp->nextp(); // iterate may cause the node to get replaced
|
||||
VL_DO_DANGLING(userIterate(itemp, WidthVP{CONTEXT_DET, PRELIM}.p()), itemp);
|
||||
}
|
||||
|
||||
AstBasicDType* dtype = VN_CAST(nodep->exprp()->dtypep(), BasicDType);
|
||||
AstNodeDType* subDTypep = nullptr;
|
||||
nodep->dtypeSetBit();
|
||||
|
||||
if (dtype && dtype->isString()) {
|
||||
nodep->dtypeSetString();
|
||||
subDTypep = nodep->findStringDType();
|
||||
} else if (dtype && dtype->isDouble()) {
|
||||
nodep->dtypeSetDouble();
|
||||
subDTypep = nodep->findDoubleDType();
|
||||
} else {
|
||||
// Take width as maximum across all items
|
||||
int width = nodep->exprp()->width();
|
||||
int mwidth = nodep->exprp()->widthMin();
|
||||
for (const AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) {
|
||||
width = std::max(width, itemp->width());
|
||||
mwidth = std::max(mwidth, itemp->widthMin());
|
||||
}
|
||||
subDTypep = nodep->findLogicDType(width, mwidth, nodep->exprp()->dtypep()->numeric());
|
||||
}
|
||||
|
||||
iterateCheck(nodep, "Dist expression", nodep->exprp(), CONTEXT_DET, FINAL, subDTypep,
|
||||
EXTEND_EXP);
|
||||
for (AstDistItem *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
|
||||
nextip
|
||||
= VN_AS(itemp->nextp(), DistItem); // iterate may cause the node to get replaced
|
||||
iterateCheck(nodep, "Dist Item", itemp, CONTEXT_DET, FINAL, subDTypep, EXTEND_EXP);
|
||||
}
|
||||
|
||||
if (debug() >= 9) nodep->dumpTree("- dist-out: ");
|
||||
nodep->dtypep(subDTypep);
|
||||
}
|
||||
|
||||
void visit(AstInside* nodep) override {
|
||||
userIterateAndNext(nodep->exprp(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||
for (AstNode *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) {
|
||||
|
|
|
|||
|
|
@ -5057,7 +5057,7 @@ expr<nodeExprp>: // IEEE: part of expression/constant_expression/
|
|||
//
|
||||
// // IEEE: expression_or_dist - here to avoid reduce problems
|
||||
// // "expr yDIST '{' dist_list '}'"
|
||||
| ~l~expr yDIST '{' dist_list '}' { $$ = $1; $4->deleteTree(); }
|
||||
| ~l~expr yDIST '{' dist_list '}' { $$ = new AstDist{$2, $1, $4}; }
|
||||
;
|
||||
|
||||
fexpr<nodeExprp>: // For use as first part of statement (disambiguates <=)
|
||||
|
|
@ -7383,7 +7383,7 @@ constraint_set<nodep>: // ==IEEE: constraint_set
|
|||
| '{' constraint_expressionList '}' { $$ = $2; }
|
||||
;
|
||||
|
||||
dist_list<nodep>: // ==IEEE: dist_list
|
||||
dist_list<distItemp>: // ==IEEE: dist_list
|
||||
dist_item { $$ = $1; }
|
||||
| dist_list ',' dist_item { $$ = addNextNull($1, $3); }
|
||||
;
|
||||
|
|
|
|||
|
|
@ -216,14 +216,14 @@
|
|||
{"type":"CONST","name":"\\\"(bvsge length header)\\\"","addr":"(RE)","loc":"d,24:14,24:16","dtypep":"(M)"}
|
||||
]}
|
||||
]},
|
||||
{"type":"STMTEXPR","name":"","addr":"(SE)","loc":"d,25:7,25:13",
|
||||
{"type":"STMTEXPR","name":"","addr":"(SE)","loc":"d,25:14,25:18",
|
||||
"exprp": [
|
||||
{"type":"CMETHODHARD","name":"hard","addr":"(TE)","loc":"d,25:7,25:13","dtypep":"(LB)",
|
||||
{"type":"CMETHODHARD","name":"hard","addr":"(TE)","loc":"d,25:14,25:18","dtypep":"(LB)",
|
||||
"fromp": [
|
||||
{"type":"VARREF","name":"constraint","addr":"(UE)","loc":"d,25:7,25:13","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
{"type":"VARREF","name":"constraint","addr":"(UE)","loc":"d,25:14,25:18","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
],
|
||||
"pinsp": [
|
||||
{"type":"CONST","name":"\\\"length\\\"","addr":"(VE)","loc":"d,25:7,25:13","dtypep":"(M)"}
|
||||
{"type":"CONST","name":"\\\"true\\\"","addr":"(VE)","loc":"d,25:14,25:18","dtypep":"(M)"}
|
||||
]}
|
||||
]}
|
||||
],"scopeNamep": []},
|
||||
|
|
|
|||
|
|
@ -159,10 +159,10 @@
|
|||
<const loc="d,24,14,24,16" name=""(bvsge length header)"" dtype_id="2"/>
|
||||
</cmethodhard>
|
||||
</stmtexpr>
|
||||
<stmtexpr loc="d,25,7,25,13">
|
||||
<cmethodhard loc="d,25,7,25,13" name="hard" dtype_id="7">
|
||||
<varref loc="d,25,7,25,13" name="constraint" dtype_id="8"/>
|
||||
<const loc="d,25,7,25,13" name=""length"" dtype_id="2"/>
|
||||
<stmtexpr loc="d,25,14,25,18">
|
||||
<cmethodhard loc="d,25,14,25,18" name="hard" dtype_id="7">
|
||||
<varref loc="d,25,14,25,18" name="constraint" dtype_id="8"/>
|
||||
<const loc="d,25,14,25,18" name=""true"" dtype_id="2"/>
|
||||
</cmethodhard>
|
||||
</stmtexpr>
|
||||
</task>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
%Warning-CONSTRAINTIGN: t/t_randomize.v:22:14: Constraint expression ignored (unsupported)
|
||||
: ... note: In instance 't'
|
||||
22 | length dist { [0:1], [2:5] :/ 2, 6 := 6, 7 := 10, 1};
|
||||
| ^~~~
|
||||
... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest
|
||||
... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message.
|
||||
%Warning-CONSTRAINTIGN: t/t_randomize.v:37:7: Constraint expression ignored (unsupported)
|
||||
: ... note: In instance 't'
|
||||
37 | foreach (array[i]) {
|
||||
| ^~~~~~~
|
||||
... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest
|
||||
... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message.
|
||||
%Warning-CONSTRAINTIGN: t/t_randomize.v:40:7: Constraint expression ignored (unsupported)
|
||||
: ... note: In instance 't'
|
||||
40 | unique { array[0], array[1] };
|
||||
|
|
|
|||
Loading…
Reference in New Issue